src/stdlib/SDL_string.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 21 Apr 2016 03:16:44 -0400
changeset 11729 d1ce8396c356
parent 11610 6dea196ecbcb
child 11811 5d94cb6b24d3
permissions -rw-r--r--
Initial shot at a renderer target for Apple's Metal API.

This isn't complete, but is enough to run testsprite2. It's currently
Mac-only; with a little work to figure out how to properly glue in a Metal
layer to a UIView, this will likely work on iOS, too.

This is only wired up to the configure script right now, and disabled by
default. CMake and Xcode still need their bits filled in as appropriate.
slouken@1330
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
slouken@1330
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@1330
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@1330
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@1330
    20
*/
slouken@10604
    21
#if defined(__clang_analyzer__)
icculus@9306
    22
#define SDL_DISABLE_ANALYZE_MACROS 1
icculus@9306
    23
#endif
icculus@9306
    24
icculus@8093
    25
#include "../SDL_internal.h"
slouken@1330
    26
slouken@1330
    27
/* This file contains portable string manipulation functions for SDL */
slouken@1330
    28
slouken@1354
    29
#include "SDL_stdinc.h"
slouken@1330
    30
slouken@10609
    31
#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOL) || !defined(HAVE_STRTOUL)  || !defined(HAVE_STRTOLL) || !defined(HAVE_STRTOULL) || !defined(HAVE_STRTOD)
slouken@1354
    32
#define SDL_isupperhex(X)   (((X) >= 'A') && ((X) <= 'F'))
slouken@1354
    33
#define SDL_islowerhex(X)   (((X) >= 'a') && ((X) <= 'f'))
slouken@10609
    34
#endif
slouken@1330
    35
dewyatt@4754
    36
#define UTF8_IsLeadByte(c) ((c) >= 0xC0 && (c) <= 0xF4)
dewyatt@4754
    37
#define UTF8_IsTrailingByte(c) ((c) >= 0x80 && (c) <= 0xBF)
dewyatt@4754
    38
slouken@6044
    39
static int UTF8_TrailingBytes(unsigned char c)
dewyatt@4754
    40
{
slouken@6029
    41
    if (c >= 0xC0 && c <= 0xDF)
dewyatt@4754
    42
        return 1;
dewyatt@4754
    43
    else if (c >= 0xE0 && c <= 0xEF)
dewyatt@4754
    44
        return 2;
dewyatt@4754
    45
    else if (c >= 0xF0 && c <= 0xF4)
dewyatt@4754
    46
        return 3;
dewyatt@4754
    47
    else
dewyatt@4754
    48
        return 0;
dewyatt@4754
    49
}
dewyatt@4754
    50
icculus@8089
    51
#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOL)
slouken@1895
    52
static size_t
slouken@1895
    53
SDL_ScanLong(const char *text, int radix, long *valuep)
slouken@1330
    54
{
slouken@1330
    55
    const char *textstart = text;
slouken@1330
    56
    long value = 0;
slouken@1330
    57
    SDL_bool negative = SDL_FALSE;
slouken@1330
    58
slouken@1895
    59
    if (*text == '-') {
slouken@1330
    60
        negative = SDL_TRUE;
slouken@1330
    61
        ++text;
slouken@1330
    62
    }
slouken@1895
    63
    if (radix == 16 && SDL_strncmp(text, "0x", 2) == 0) {
slouken@1330
    64
        text += 2;
slouken@1330
    65
    }
slouken@1895
    66
    for (;;) {
slouken@1330
    67
        int v;
icculus@2092
    68
        if (SDL_isdigit((unsigned char) *text)) {
slouken@1330
    69
            v = *text - '0';
slouken@1895
    70
        } else if (radix == 16 && SDL_isupperhex(*text)) {
slouken@1330
    71
            v = 10 + (*text - 'A');
slouken@1895
    72
        } else if (radix == 16 && SDL_islowerhex(*text)) {
slouken@1330
    73
            v = 10 + (*text - 'a');
slouken@1330
    74
        } else {
slouken@1330
    75
            break;
slouken@1330
    76
        }
slouken@1330
    77
        value *= radix;
slouken@1330
    78
        value += v;
slouken@1330
    79
        ++text;
slouken@1330
    80
    }
slouken@11227
    81
    if (valuep && text > textstart) {
slouken@1895
    82
        if (negative && value) {
slouken@1330
    83
            *valuep = -value;
slouken@1330
    84
        } else {
slouken@1330
    85
            *valuep = value;
slouken@1330
    86
        }
slouken@1330
    87
    }
slouken@1330
    88
    return (text - textstart);
slouken@1330
    89
}
slouken@1330
    90
#endif
slouken@1330
    91
icculus@8089
    92
#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOUL) || !defined(HAVE_STRTOD)
slouken@1895
    93
static size_t
slouken@1895
    94
SDL_ScanUnsignedLong(const char *text, int radix, unsigned long *valuep)
slouken@1330
    95
{
slouken@1330
    96
    const char *textstart = text;
slouken@1330
    97
    unsigned long value = 0;
slouken@1330
    98
slouken@1895
    99
    if (radix == 16 && SDL_strncmp(text, "0x", 2) == 0) {
slouken@1330
   100
        text += 2;
slouken@1330
   101
    }
slouken@1895
   102
    for (;;) {
slouken@1330
   103
        int v;
icculus@2092
   104
        if (SDL_isdigit((unsigned char) *text)) {
slouken@1330
   105
            v = *text - '0';
slouken@1895
   106
        } else if (radix == 16 && SDL_isupperhex(*text)) {
slouken@1330
   107
            v = 10 + (*text - 'A');
slouken@1895
   108
        } else if (radix == 16 && SDL_islowerhex(*text)) {
slouken@1330
   109
            v = 10 + (*text - 'a');
slouken@1330
   110
        } else {
slouken@1330
   111
            break;
slouken@1330
   112
        }
slouken@1330
   113
        value *= radix;
slouken@1330
   114
        value += v;
slouken@1330
   115
        ++text;
slouken@1330
   116
    }
slouken@11227
   117
    if (valuep && text > textstart) {
slouken@1330
   118
        *valuep = value;
slouken@1330
   119
    }
slouken@1330
   120
    return (text - textstart);
slouken@1330
   121
}
slouken@1330
   122
#endif
slouken@1330
   123
icculus@8089
   124
#ifndef HAVE_VSSCANF
slouken@1895
   125
static size_t
slouken@1895
   126
SDL_ScanUintPtrT(const char *text, int radix, uintptr_t * valuep)
slouken@1456
   127
{
slouken@1456
   128
    const char *textstart = text;
slouken@1456
   129
    uintptr_t value = 0;
slouken@1456
   130
slouken@1895
   131
    if (radix == 16 && SDL_strncmp(text, "0x", 2) == 0) {
slouken@1456
   132
        text += 2;
slouken@1456
   133
    }
slouken@1895
   134
    for (;;) {
slouken@1456
   135
        int v;
icculus@2092
   136
        if (SDL_isdigit((unsigned char) *text)) {
slouken@1456
   137
            v = *text - '0';
slouken@1895
   138
        } else if (radix == 16 && SDL_isupperhex(*text)) {
slouken@1456
   139
            v = 10 + (*text - 'A');
slouken@1895
   140
        } else if (radix == 16 && SDL_islowerhex(*text)) {
slouken@1456
   141
            v = 10 + (*text - 'a');
slouken@1456
   142
        } else {
slouken@1456
   143
            break;
slouken@1456
   144
        }
slouken@1456
   145
        value *= radix;
slouken@1456
   146
        value += v;
slouken@1456
   147
        ++text;
slouken@1456
   148
    }
slouken@11227
   149
    if (valuep && text > textstart) {
slouken@1456
   150
        *valuep = value;
slouken@1456
   151
    }
slouken@1456
   152
    return (text - textstart);
slouken@1456
   153
}
slouken@1456
   154
#endif
slouken@1456
   155
icculus@8089
   156
#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOLL)
slouken@1895
   157
static size_t
slouken@1895
   158
SDL_ScanLongLong(const char *text, int radix, Sint64 * valuep)
slouken@1330
   159
{
slouken@1330
   160
    const char *textstart = text;
slouken@1330
   161
    Sint64 value = 0;
slouken@1330
   162
    SDL_bool negative = SDL_FALSE;
slouken@1330
   163
slouken@1895
   164
    if (*text == '-') {
slouken@1330
   165
        negative = SDL_TRUE;
slouken@1330
   166
        ++text;
slouken@1330
   167
    }
slouken@1895
   168
    if (radix == 16 && SDL_strncmp(text, "0x", 2) == 0) {
slouken@1330
   169
        text += 2;
slouken@1330
   170
    }
slouken@1895
   171
    for (;;) {
slouken@1330
   172
        int v;
icculus@2092
   173
        if (SDL_isdigit((unsigned char) *text)) {
slouken@1330
   174
            v = *text - '0';
slouken@1895
   175
        } else if (radix == 16 && SDL_isupperhex(*text)) {
slouken@1330
   176
            v = 10 + (*text - 'A');
slouken@1895
   177
        } else if (radix == 16 && SDL_islowerhex(*text)) {
slouken@1330
   178
            v = 10 + (*text - 'a');
slouken@1330
   179
        } else {
slouken@1330
   180
            break;
slouken@1330
   181
        }
slouken@1330
   182
        value *= radix;
slouken@1330
   183
        value += v;
slouken@1330
   184
        ++text;
slouken@1330
   185
    }
slouken@11227
   186
    if (valuep && text > textstart) {
slouken@1895
   187
        if (negative && value) {
slouken@1330
   188
            *valuep = -value;
slouken@1330
   189
        } else {
slouken@1330
   190
            *valuep = value;
slouken@1330
   191
        }
slouken@1330
   192
    }
slouken@1330
   193
    return (text - textstart);
slouken@1330
   194
}
slouken@1330
   195
#endif
slouken@1330
   196
icculus@8089
   197
#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOULL)
slouken@1895
   198
static size_t
slouken@1895
   199
SDL_ScanUnsignedLongLong(const char *text, int radix, Uint64 * valuep)
slouken@1330
   200
{
slouken@1330
   201
    const char *textstart = text;
slouken@1330
   202
    Uint64 value = 0;
slouken@1330
   203
slouken@1895
   204
    if (radix == 16 && SDL_strncmp(text, "0x", 2) == 0) {
slouken@1330
   205
        text += 2;
slouken@1330
   206
    }
slouken@1895
   207
    for (;;) {
slouken@1330
   208
        int v;
icculus@2092
   209
        if (SDL_isdigit((unsigned char) *text)) {
slouken@1330
   210
            v = *text - '0';
slouken@1895
   211
        } else if (radix == 16 && SDL_isupperhex(*text)) {
slouken@1330
   212
            v = 10 + (*text - 'A');
slouken@1895
   213
        } else if (radix == 16 && SDL_islowerhex(*text)) {
slouken@1330
   214
            v = 10 + (*text - 'a');
slouken@1330
   215
        } else {
slouken@1330
   216
            break;
slouken@1330
   217
        }
slouken@1330
   218
        value *= radix;
slouken@1330
   219
        value += v;
slouken@1330
   220
        ++text;
slouken@1330
   221
    }
slouken@11227
   222
    if (valuep && text > textstart) {
slouken@1330
   223
        *valuep = value;
slouken@1330
   224
    }
slouken@1330
   225
    return (text - textstart);
slouken@1330
   226
}
slouken@1330
   227
#endif
slouken@1330
   228
icculus@8089
   229
#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOD)
slouken@1895
   230
static size_t
slouken@1895
   231
SDL_ScanFloat(const char *text, double *valuep)
slouken@1330
   232
{
slouken@1330
   233
    const char *textstart = text;
slouken@1330
   234
    unsigned long lvalue = 0;
slouken@1330
   235
    double value = 0.0;
slouken@1330
   236
    SDL_bool negative = SDL_FALSE;
slouken@1330
   237
slouken@1895
   238
    if (*text == '-') {
slouken@1330
   239
        negative = SDL_TRUE;
slouken@1330
   240
        ++text;
slouken@1330
   241
    }
slouken@1330
   242
    text += SDL_ScanUnsignedLong(text, 10, &lvalue);
slouken@1330
   243
    value += lvalue;
slouken@1895
   244
    if (*text == '.') {
slouken@1330
   245
        int mult = 10;
slouken@1330
   246
        ++text;
icculus@2092
   247
        while (SDL_isdigit((unsigned char) *text)) {
slouken@1330
   248
            lvalue = *text - '0';
slouken@1895
   249
            value += (double) lvalue / mult;
slouken@1330
   250
            mult *= 10;
slouken@1330
   251
            ++text;
slouken@1330
   252
        }
slouken@1330
   253
    }
slouken@11227
   254
    if (valuep && text > textstart) {
slouken@1895
   255
        if (negative && value) {
slouken@1330
   256
            *valuep = -value;
slouken@1330
   257
        } else {
slouken@1330
   258
            *valuep = value;
slouken@1330
   259
        }
slouken@1330
   260
    }
slouken@1330
   261
    return (text - textstart);
slouken@1330
   262
}
slouken@1330
   263
#endif
slouken@1330
   264
slouken@1895
   265
void *
slouken@8820
   266
SDL_memset(SDL_OUT_BYTECAP(len) void *dst, int c, size_t len)
slouken@1330
   267
{
slouken@7351
   268
#if defined(HAVE_MEMSET)
slouken@7351
   269
    return memset(dst, c, len);
slouken@7351
   270
#else
yuriks@8779
   271
    size_t left;
slouken@5325
   272
    Uint32 *dstp4;
yuriks@8779
   273
    Uint8 *dstp1 = (Uint8 *) dst;
slouken@5325
   274
    Uint32 value4 = (c | (c << 8) | (c << 16) | (c << 24));
slouken@5325
   275
    Uint8 value1 = (Uint8) c;
slouken@5325
   276
yuriks@8779
   277
    /* The destination pointer needs to be aligned on a 4-byte boundary to
yuriks@8779
   278
     * execute a 32-bit set. Set first bytes manually if needed until it is
yuriks@8779
   279
     * aligned. */
yuriks@8779
   280
    while ((intptr_t)dstp1 & 0x3) {
yuriks@8779
   281
        if (len--) {
yuriks@8779
   282
            *dstp1++ = value1;
yuriks@8779
   283
        } else {
yuriks@8779
   284
            return dst;
yuriks@8779
   285
        }
yuriks@8779
   286
    }
yuriks@8779
   287
yuriks@8779
   288
    dstp4 = (Uint32 *) dstp1;
yuriks@8779
   289
    left = (len % 4);
slouken@5325
   290
    len /= 4;
slouken@5325
   291
    while (len--) {
slouken@5325
   292
        *dstp4++ = value4;
slouken@1330
   293
    }
slouken@5325
   294
slouken@5325
   295
    dstp1 = (Uint8 *) dstp4;
slouken@5325
   296
    switch (left) {
slouken@5325
   297
    case 3:
slouken@5325
   298
        *dstp1++ = value1;
slouken@5325
   299
    case 2:
slouken@5325
   300
        *dstp1++ = value1;
slouken@5325
   301
    case 1:
slouken@5325
   302
        *dstp1++ = value1;
slouken@1330
   303
    }
slouken@5325
   304
slouken@1330
   305
    return dst;
slouken@7351
   306
#endif /* HAVE_MEMSET */
slouken@1330
   307
}
slouken@1330
   308
slouken@1895
   309
void *
slouken@8820
   310
SDL_memcpy(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len)
slouken@1330
   311
{
slouken@7236
   312
#ifdef __GNUC__
slouken@7236
   313
    /* Presumably this is well tuned for speed.
slouken@7236
   314
       On my machine this is twice as fast as the C code below.
slouken@7236
   315
     */
slouken@7236
   316
    return __builtin_memcpy(dst, src, len);
slouken@7351
   317
#elif defined(HAVE_MEMCPY)
slouken@7351
   318
    return memcpy(dst, src, len);
slouken@7351
   319
#elif defined(HAVE_BCOPY)
slouken@7351
   320
    bcopy(src, dst, len);
slouken@7351
   321
    return dst;
slouken@7236
   322
#else
slouken@7236
   323
    /* GCC 4.9.0 with -O3 will generate movaps instructions with the loop
slouken@7236
   324
       using Uint32* pointers, so we need to make sure the pointers are
slouken@7236
   325
       aligned before we loop using them.
slouken@7236
   326
     */
slouken@7236
   327
    if (((intptr_t)src & 0x3) || ((intptr_t)dst & 0x3)) {
slouken@7236
   328
        /* Do an unaligned byte copy */
slouken@7236
   329
        Uint8 *srcp1 = (Uint8 *)src;
slouken@7236
   330
        Uint8 *dstp1 = (Uint8 *)dst;
slouken@5325
   331
slouken@7236
   332
        while (len--) {
slouken@7236
   333
            *dstp1++ = *srcp1++;
slouken@7236
   334
        }
slouken@7236
   335
    } else {
slouken@7236
   336
        size_t left = (len % 4);
slouken@7236
   337
        Uint32 *srcp4, *dstp4;
slouken@7236
   338
        Uint8 *srcp1, *dstp1;
slouken@7236
   339
slouken@7236
   340
        srcp4 = (Uint32 *) src;
slouken@7236
   341
        dstp4 = (Uint32 *) dst;
slouken@7236
   342
        len /= 4;
slouken@7236
   343
        while (len--) {
slouken@7236
   344
            *dstp4++ = *srcp4++;
slouken@7236
   345
        }
slouken@7236
   346
slouken@7236
   347
        srcp1 = (Uint8 *) srcp4;
slouken@7236
   348
        dstp1 = (Uint8 *) dstp4;
slouken@7236
   349
        switch (left) {
slouken@7236
   350
        case 3:
slouken@7236
   351
            *dstp1++ = *srcp1++;
slouken@7236
   352
        case 2:
slouken@7236
   353
            *dstp1++ = *srcp1++;
slouken@7236
   354
        case 1:
slouken@7236
   355
            *dstp1++ = *srcp1++;
slouken@7236
   356
        }
slouken@1330
   357
    }
slouken@1330
   358
    return dst;
slouken@7236
   359
#endif /* __GNUC__ */
slouken@1330
   360
}
slouken@1330
   361
slouken@1895
   362
void *
slouken@8820
   363
SDL_memmove(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len)
slouken@1330
   364
{
slouken@7351
   365
#if defined(HAVE_MEMMOVE)
slouken@7351
   366
    return memmove(dst, src, len);
slouken@7351
   367
#else
slouken@1895
   368
    char *srcp = (char *) src;
slouken@1895
   369
    char *dstp = (char *) dst;
slouken@5325
   370
slouken@5325
   371
    if (src < dst) {
slouken@5325
   372
        srcp += len - 1;
slouken@5325
   373
        dstp += len - 1;
slouken@5325
   374
        while (len--) {
slouken@5325
   375
            *dstp-- = *srcp--;
slouken@5325
   376
        }
slouken@5325
   377
    } else {
slouken@5325
   378
        while (len--) {
slouken@5325
   379
            *dstp++ = *srcp++;
slouken@5325
   380
        }
slouken@1330
   381
    }
slouken@1330
   382
    return dst;
slouken@7351
   383
#endif /* HAVE_MEMMOVE */
slouken@1330
   384
}
slouken@1330
   385
slouken@1895
   386
int
slouken@1895
   387
SDL_memcmp(const void *s1, const void *s2, size_t len)
slouken@1330
   388
{
slouken@7351
   389
#if defined(HAVE_MEMCMP)
slouken@7351
   390
    return memcmp(s1, s2, len);
slouken@7351
   391
#else
slouken@1895
   392
    char *s1p = (char *) s1;
slouken@1895
   393
    char *s2p = (char *) s2;
slouken@1895
   394
    while (len--) {
slouken@1895
   395
        if (*s1p != *s2p) {
slouken@1330
   396
            return (*s1p - *s2p);
slouken@1895
   397
        }
slouken@1895
   398
        ++s1p;
slouken@1895
   399
        ++s2p;
slouken@1330
   400
    }
slouken@1330
   401
    return 0;
slouken@7351
   402
#endif /* HAVE_MEMCMP */
slouken@1330
   403
}
slouken@1330
   404
slouken@1895
   405
size_t
slouken@1895
   406
SDL_strlen(const char *string)
slouken@1330
   407
{
slouken@7351
   408
#if defined(HAVE_STRLEN)
slouken@7352
   409
    return strlen(string);
slouken@7351
   410
#else
slouken@1330
   411
    size_t len = 0;
slouken@1895
   412
    while (*string++) {
slouken@1330
   413
        ++len;
slouken@1330
   414
    }
slouken@1330
   415
    return len;
slouken@7351
   416
#endif /* HAVE_STRLEN */
slouken@1330
   417
}
slouken@1330
   418
slouken@1901
   419
size_t
slouken@1903
   420
SDL_wcslen(const wchar_t * string)
slouken@1901
   421
{
slouken@7351
   422
#if defined(HAVE_WCSLEN)
slouken@7352
   423
    return wcslen(string);
slouken@7351
   424
#else
slouken@1901
   425
    size_t len = 0;
slouken@1901
   426
    while (*string++) {
slouken@1901
   427
        ++len;
slouken@1901
   428
    }
slouken@1901
   429
    return len;
slouken@7351
   430
#endif /* HAVE_WCSLEN */
slouken@1901
   431
}
slouken@1901
   432
dewyatt@4758
   433
size_t
slouken@8820
   434
SDL_wcslcpy(SDL_OUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen)
dewyatt@4758
   435
{
slouken@7351
   436
#if defined(HAVE_WCSLCPY)
slouken@7351
   437
    return wcslcpy(dst, src, maxlen);
slouken@7351
   438
#else
dewyatt@4758
   439
    size_t srclen = SDL_wcslen(src);
dewyatt@4758
   440
    if (maxlen > 0) {
dewyatt@4758
   441
        size_t len = SDL_min(srclen, maxlen - 1);
dewyatt@4758
   442
        SDL_memcpy(dst, src, len * sizeof(wchar_t));
dewyatt@4758
   443
        dst[len] = '\0';
dewyatt@4758
   444
    }
dewyatt@4758
   445
    return srclen;
slouken@7351
   446
#endif /* HAVE_WCSLCPY */
dewyatt@4758
   447
}
dewyatt@4758
   448
dewyatt@4758
   449
size_t
slouken@8820
   450
SDL_wcslcat(SDL_INOUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen)
dewyatt@4758
   451
{
slouken@7351
   452
#if defined(HAVE_WCSLCAT)
slouken@7351
   453
    return wcslcat(dst, src, maxlen);
slouken@7351
   454
#else
dewyatt@4758
   455
    size_t dstlen = SDL_wcslen(dst);
dewyatt@4758
   456
    size_t srclen = SDL_wcslen(src);
dewyatt@4758
   457
    if (dstlen < maxlen) {
dewyatt@4758
   458
        SDL_wcslcpy(dst + dstlen, src, maxlen - dstlen);
dewyatt@4758
   459
    }
dewyatt@4758
   460
    return dstlen + srclen;
slouken@7351
   461
#endif /* HAVE_WCSLCAT */
dewyatt@4758
   462
}
dewyatt@4758
   463
slouken@11265
   464
int
slouken@11265
   465
SDL_wcscmp(const wchar_t *str1, const wchar_t *str2)
slouken@11265
   466
{
slouken@11265
   467
#if defined(HAVE_WCSCMP)
slouken@11265
   468
    return wcscmp(str1, str2);
slouken@11265
   469
#else
slouken@11265
   470
    while (*str1 && *str2) {
slouken@11265
   471
        if (*str1 != *str2)
slouken@11265
   472
            break;
slouken@11265
   473
        ++str1;
slouken@11265
   474
        ++str2;
slouken@11265
   475
    }
slouken@11265
   476
    return (int)(*str1 - *str2);
slouken@11265
   477
#endif /* HAVE_WCSCMP */
slouken@11265
   478
}
slouken@11265
   479
slouken@1895
   480
size_t
slouken@8820
   481
SDL_strlcpy(SDL_OUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen)
slouken@1330
   482
{
slouken@7351
   483
#if defined(HAVE_STRLCPY)
slouken@7351
   484
    return strlcpy(dst, src, maxlen);
slouken@7351
   485
#else
slouken@1379
   486
    size_t srclen = SDL_strlen(src);
slouken@1895
   487
    if (maxlen > 0) {
slouken@1895
   488
        size_t len = SDL_min(srclen, maxlen - 1);
slouken@1379
   489
        SDL_memcpy(dst, src, len);
slouken@1379
   490
        dst[len] = '\0';
slouken@1330
   491
    }
slouken@1379
   492
    return srclen;
slouken@7351
   493
#endif /* HAVE_STRLCPY */
slouken@1330
   494
}
slouken@1330
   495
icculus@11052
   496
size_t
icculus@11052
   497
SDL_utf8strlcpy(SDL_OUT_Z_CAP(dst_bytes) char *dst, const char *src, size_t dst_bytes)
dewyatt@4754
   498
{
dewyatt@4754
   499
    size_t src_bytes = SDL_strlen(src);
dewyatt@4754
   500
    size_t bytes = SDL_min(src_bytes, dst_bytes - 1);
slouken@5076
   501
    size_t i = 0;
dewyatt@4754
   502
    char trailing_bytes = 0;
dewyatt@4754
   503
    if (bytes)
dewyatt@4754
   504
    {
dewyatt@4754
   505
        unsigned char c = (unsigned char)src[bytes - 1];
dewyatt@4754
   506
        if (UTF8_IsLeadByte(c))
dewyatt@4754
   507
            --bytes;
dewyatt@4754
   508
        else if (UTF8_IsTrailingByte(c))
dewyatt@4754
   509
        {
dewyatt@4754
   510
            for (i = bytes - 1; i != 0; --i)
dewyatt@4754
   511
            {
dewyatt@4754
   512
                c = (unsigned char)src[i];
dewyatt@4754
   513
                trailing_bytes = UTF8_TrailingBytes(c);
dewyatt@4754
   514
                if (trailing_bytes)
dewyatt@4754
   515
                {
dewyatt@4754
   516
                    if (bytes - i != trailing_bytes + 1)
dewyatt@4754
   517
                        bytes = i;
dewyatt@4754
   518
dewyatt@4754
   519
                    break;
dewyatt@4754
   520
                }
dewyatt@4754
   521
            }
dewyatt@4754
   522
        }
dewyatt@4754
   523
        SDL_memcpy(dst, src, bytes);
dewyatt@4754
   524
    }
dewyatt@4754
   525
    dst[bytes] = '\0';
dewyatt@4754
   526
    return bytes;
dewyatt@4754
   527
}
dewyatt@4754
   528
slouken@1895
   529
size_t
icculus@11049
   530
SDL_utf8strlen(const char *str)
icculus@11049
   531
{
icculus@11049
   532
    size_t retval = 0;
icculus@11049
   533
    const char *p = str;
icculus@11049
   534
    char ch;
icculus@11049
   535
icculus@11049
   536
    while ((ch = *(p++))) {
icculus@11049
   537
        /* if top two bits are 1 and 0, it's a continuation byte. */
icculus@11049
   538
        if ((ch & 0xc0) != 0x80) {
icculus@11049
   539
            retval++;
icculus@11049
   540
        }
icculus@11049
   541
    }
icculus@11049
   542
    
icculus@11049
   543
    return retval;
icculus@11049
   544
}
icculus@11049
   545
icculus@11049
   546
size_t
slouken@8820
   547
SDL_strlcat(SDL_INOUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen)
slouken@1330
   548
{
slouken@7351
   549
#if defined(HAVE_STRLCAT)
slouken@7351
   550
    return strlcat(dst, src, maxlen);
slouken@7351
   551
#else
slouken@1379
   552
    size_t dstlen = SDL_strlen(dst);
slouken@1379
   553
    size_t srclen = SDL_strlen(src);
slouken@1895
   554
    if (dstlen < maxlen) {
slouken@1895
   555
        SDL_strlcpy(dst + dstlen, src, maxlen - dstlen);
slouken@1330
   556
    }
slouken@1895
   557
    return dstlen + srclen;
slouken@7351
   558
#endif /* HAVE_STRLCAT */
slouken@1330
   559
}
slouken@1330
   560
slouken@1895
   561
char *
slouken@1895
   562
SDL_strdup(const char *string)
slouken@1341
   563
{
slouken@1895
   564
    size_t len = SDL_strlen(string) + 1;
slouken@1379
   565
    char *newstr = SDL_malloc(len);
slouken@1895
   566
    if (newstr) {
slouken@1379
   567
        SDL_strlcpy(newstr, string, len);
slouken@1341
   568
    }
slouken@1341
   569
    return newstr;
slouken@1341
   570
}
slouken@1341
   571
slouken@1895
   572
char *
slouken@1895
   573
SDL_strrev(char *string)
slouken@1330
   574
{
slouken@7351
   575
#if defined(HAVE__STRREV)
slouken@7353
   576
    return _strrev(string);
slouken@7351
   577
#else
slouken@1330
   578
    size_t len = SDL_strlen(string);
slouken@1330
   579
    char *a = &string[0];
slouken@1895
   580
    char *b = &string[len - 1];
slouken@1330
   581
    len /= 2;
slouken@1895
   582
    while (len--) {
slouken@1330
   583
        char c = *a;
slouken@1330
   584
        *a++ = *b;
slouken@1330
   585
        *b-- = c;
slouken@1330
   586
    }
slouken@1330
   587
    return string;
slouken@7351
   588
#endif /* HAVE__STRREV */
slouken@1330
   589
}
slouken@1330
   590
slouken@1895
   591
char *
slouken@1895
   592
SDL_strupr(char *string)
slouken@1330
   593
{
slouken@7351
   594
#if defined(HAVE__STRUPR)
slouken@7353
   595
    return _strupr(string);
slouken@7351
   596
#else
slouken@1330
   597
    char *bufp = string;
slouken@1895
   598
    while (*bufp) {
icculus@2092
   599
        *bufp = SDL_toupper((unsigned char) *bufp);
slouken@1895
   600
        ++bufp;
slouken@1330
   601
    }
slouken@1330
   602
    return string;
slouken@7351
   603
#endif /* HAVE__STRUPR */
slouken@1330
   604
}
slouken@1330
   605
slouken@1895
   606
char *
slouken@1895
   607
SDL_strlwr(char *string)
slouken@1330
   608
{
slouken@7351
   609
#if defined(HAVE__STRLWR)
slouken@7353
   610
    return _strlwr(string);
slouken@7351
   611
#else
slouken@1330
   612
    char *bufp = string;
slouken@1895
   613
    while (*bufp) {
icculus@2092
   614
        *bufp = SDL_tolower((unsigned char) *bufp);
slouken@1895
   615
        ++bufp;
slouken@1330
   616
    }
slouken@1330
   617
    return string;
slouken@7351
   618
#endif /* HAVE__STRLWR */
slouken@1330
   619
}
slouken@1330
   620
slouken@1895
   621
char *
slouken@1895
   622
SDL_strchr(const char *string, int c)
slouken@1330
   623
{
slouken@7351
   624
#ifdef HAVE_STRCHR
slouken@7352
   625
    return SDL_const_cast(char*,strchr(string, c));
slouken@7351
   626
#elif defined(HAVE_INDEX)
slouken@7352
   627
    return SDL_const_cast(char*,index(string, c));
slouken@7351
   628
#else
slouken@1895
   629
    while (*string) {
slouken@1895
   630
        if (*string == c) {
slouken@1895
   631
            return (char *) string;
slouken@1330
   632
        }
slouken@1895
   633
        ++string;
slouken@1330
   634
    }
slouken@1330
   635
    return NULL;
slouken@7351
   636
#endif /* HAVE_STRCHR */
slouken@1330
   637
}
slouken@1330
   638
slouken@1895
   639
char *
slouken@1895
   640
SDL_strrchr(const char *string, int c)
slouken@1330
   641
{
slouken@7351
   642
#ifdef HAVE_STRRCHR
slouken@7352
   643
    return SDL_const_cast(char*,strrchr(string, c));
slouken@7351
   644
#elif defined(HAVE_RINDEX)
slouken@7352
   645
    return SDL_const_cast(char*,rindex(string, c));
slouken@7351
   646
#else
slouken@1336
   647
    const char *bufp = string + SDL_strlen(string) - 1;
slouken@1895
   648
    while (bufp >= string) {
slouken@1895
   649
        if (*bufp == c) {
slouken@1895
   650
            return (char *) bufp;
slouken@1330
   651
        }
slouken@1895
   652
        --bufp;
slouken@1330
   653
    }
slouken@1330
   654
    return NULL;
slouken@7351
   655
#endif /* HAVE_STRRCHR */
slouken@1330
   656
}
slouken@1330
   657
slouken@1895
   658
char *
slouken@1895
   659
SDL_strstr(const char *haystack, const char *needle)
slouken@1330
   660
{
slouken@7351
   661
#if defined(HAVE_STRSTR)
slouken@7351
   662
    return SDL_const_cast(char*,strstr(haystack, needle));
slouken@7351
   663
#else
slouken@1336
   664
    size_t length = SDL_strlen(needle);
slouken@1895
   665
    while (*haystack) {
slouken@1895
   666
        if (SDL_strncmp(haystack, needle, length) == 0) {
slouken@1895
   667
            return (char *) haystack;
slouken@1330
   668
        }
slouken@1895
   669
        ++haystack;
slouken@1330
   670
    }
slouken@1330
   671
    return NULL;
slouken@7351
   672
#endif /* HAVE_STRSTR */
slouken@1330
   673
}
slouken@1330
   674
slouken@7353
   675
#if !defined(HAVE__LTOA) || !defined(HAVE__I64TOA) || \
slouken@7353
   676
    !defined(HAVE__ULTOA) || !defined(HAVE__UI64TOA)
slouken@1330
   677
static const char ntoa_table[] = {
slouken@1330
   678
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
slouken@1330
   679
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
slouken@1330
   680
    'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
slouken@1330
   681
    'U', 'V', 'W', 'X', 'Y', 'Z'
slouken@1330
   682
};
slouken@1330
   683
#endif /* ntoa() conversion table */
slouken@1330
   684
slouken@7351
   685
char *
slouken@7353
   686
SDL_itoa(int value, char *string, int radix)
slouken@7351
   687
{
slouken@7351
   688
#ifdef HAVE_ITOA
slouken@7353
   689
    return itoa(value, string, radix);
icculus@7003
   690
#else
slouken@7353
   691
    return SDL_ltoa((long)value, string, radix);
slouken@7351
   692
#endif /* HAVE_ITOA */
slouken@7351
   693
}
slouken@7351
   694
slouken@7351
   695
char *
slouken@7353
   696
SDL_uitoa(unsigned int value, char *string, int radix)
slouken@7351
   697
{
slouken@7351
   698
#ifdef HAVE__UITOA
slouken@7353
   699
    return _uitoa(value, string, radix);
slouken@7351
   700
#else
slouken@7353
   701
    return SDL_ultoa((unsigned long)value, string, radix);
slouken@7351
   702
#endif /* HAVE__UITOA */
slouken@7351
   703
}
slouken@7351
   704
slouken@1895
   705
char *
slouken@1895
   706
SDL_ltoa(long value, char *string, int radix)
slouken@1330
   707
{
slouken@7351
   708
#if defined(HAVE__LTOA)
slouken@7353
   709
    return _ltoa(value, string, radix);
slouken@7351
   710
#else
slouken@1330
   711
    char *bufp = string;
slouken@1330
   712
slouken@1895
   713
    if (value < 0) {
slouken@1330
   714
        *bufp++ = '-';
slouken@8059
   715
        SDL_ultoa(-value, bufp, radix);
slouken@1330
   716
    } else {
slouken@8059
   717
        SDL_ultoa(value, bufp, radix);
slouken@1330
   718
    }
slouken@1330
   719
slouken@1330
   720
    return string;
slouken@7351
   721
#endif /* HAVE__LTOA */
slouken@1330
   722
}
slouken@1330
   723
slouken@1895
   724
char *
slouken@1895
   725
SDL_ultoa(unsigned long value, char *string, int radix)
slouken@1330
   726
{
slouken@7351
   727
#if defined(HAVE__ULTOA)
slouken@7353
   728
    return _ultoa(value, string, radix);
slouken@7351
   729
#else
slouken@1330
   730
    char *bufp = string;
slouken@1330
   731
slouken@1895
   732
    if (value) {
slouken@1895
   733
        while (value > 0) {
slouken@1330
   734
            *bufp++ = ntoa_table[value % radix];
slouken@1330
   735
            value /= radix;
slouken@1330
   736
        }
slouken@1330
   737
    } else {
slouken@1330
   738
        *bufp++ = '0';
slouken@1330
   739
    }
slouken@1330
   740
    *bufp = '\0';
slouken@1330
   741
slouken@1330
   742
    /* The numbers went into the string backwards. :) */
slouken@1336
   743
    SDL_strrev(string);
slouken@1330
   744
slouken@1330
   745
    return string;
slouken@7351
   746
#endif /* HAVE__ULTOA */
slouken@1330
   747
}
slouken@1330
   748
slouken@1895
   749
char *
slouken@1895
   750
SDL_lltoa(Sint64 value, char *string, int radix)
slouken@1330
   751
{
slouken@7351
   752
#if defined(HAVE__I64TOA)
slouken@7353
   753
    return _i64toa(value, string, radix);
slouken@7351
   754
#else
slouken@1330
   755
    char *bufp = string;
slouken@1330
   756
slouken@1895
   757
    if (value < 0) {
slouken@1330
   758
        *bufp++ = '-';
slouken@8059
   759
        SDL_ulltoa(-value, bufp, radix);
slouken@1330
   760
    } else {
slouken@8059
   761
        SDL_ulltoa(value, bufp, radix);
slouken@1330
   762
    }
slouken@1330
   763
slouken@1330
   764
    return string;
slouken@7351
   765
#endif /* HAVE__I64TOA */
slouken@1330
   766
}
slouken@1330
   767
slouken@1895
   768
char *
slouken@1895
   769
SDL_ulltoa(Uint64 value, char *string, int radix)
slouken@1330
   770
{
slouken@7351
   771
#if defined(HAVE__UI64TOA)
slouken@7353
   772
    return _ui64toa(value, string, radix);
slouken@7351
   773
#else
slouken@1330
   774
    char *bufp = string;
slouken@1330
   775
slouken@1895
   776
    if (value) {
slouken@1895
   777
        while (value > 0) {
slouken@1330
   778
            *bufp++ = ntoa_table[value % radix];
slouken@1330
   779
            value /= radix;
slouken@1330
   780
        }
slouken@1330
   781
    } else {
slouken@1330
   782
        *bufp++ = '0';
slouken@1330
   783
    }
slouken@1330
   784
    *bufp = '\0';
slouken@1330
   785
slouken@1330
   786
    /* The numbers went into the string backwards. :) */
slouken@1336
   787
    SDL_strrev(string);
slouken@1330
   788
slouken@1330
   789
    return string;
slouken@7351
   790
#endif /* HAVE__UI64TOA */
slouken@1330
   791
}
slouken@1330
   792
slouken@7353
   793
int SDL_atoi(const char *string)
slouken@7351
   794
{
slouken@7351
   795
#ifdef HAVE_ATOI
slouken@7353
   796
    return atoi(string);
icculus@7003
   797
#else
slouken@7353
   798
    return SDL_strtol(string, NULL, 0);
slouken@7351
   799
#endif /* HAVE_ATOI */
slouken@7351
   800
}
slouken@7351
   801
slouken@7353
   802
double SDL_atof(const char *string)
slouken@7351
   803
{
slouken@7351
   804
#ifdef HAVE_ATOF
slouken@7353
   805
    return (double) atof(string);
slouken@7351
   806
#else
slouken@7353
   807
    return SDL_strtod(string, NULL);
slouken@7351
   808
#endif /* HAVE_ATOF */
slouken@7351
   809
}
slouken@7351
   810
slouken@7351
   811
long
slouken@7351
   812
SDL_strtol(const char *string, char **endp, int base)
slouken@7351
   813
{
slouken@7351
   814
#if defined(HAVE_STRTOL)
slouken@7352
   815
    return strtol(string, endp, base);
slouken@7351
   816
#else
slouken@7351
   817
    size_t len;
slouken@11235
   818
    long value = 0;
slouken@7351
   819
slouken@7351
   820
    if (!base) {
slouken@7351
   821
        if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
slouken@7351
   822
            base = 16;
slouken@7351
   823
        } else {
slouken@7351
   824
            base = 10;
slouken@7351
   825
        }
slouken@7351
   826
    }
slouken@7351
   827
slouken@7351
   828
    len = SDL_ScanLong(string, base, &value);
slouken@7351
   829
    if (endp) {
slouken@7351
   830
        *endp = (char *) string + len;
slouken@7351
   831
    }
slouken@7351
   832
    return value;
slouken@7351
   833
#endif /* HAVE_STRTOL */
slouken@7351
   834
}
slouken@7351
   835
slouken@7351
   836
unsigned long
slouken@7351
   837
SDL_strtoul(const char *string, char **endp, int base)
slouken@7351
   838
{
slouken@7351
   839
#if defined(HAVE_STRTOUL)
slouken@7352
   840
    return strtoul(string, endp, base);
slouken@7351
   841
#else
slouken@7351
   842
    size_t len;
slouken@11235
   843
    unsigned long value = 0;
slouken@7351
   844
slouken@7351
   845
    if (!base) {
slouken@7351
   846
        if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
slouken@7351
   847
            base = 16;
slouken@7351
   848
        } else {
slouken@7351
   849
            base = 10;
slouken@7351
   850
        }
slouken@7351
   851
    }
slouken@7351
   852
slouken@7351
   853
    len = SDL_ScanUnsignedLong(string, base, &value);
slouken@7351
   854
    if (endp) {
slouken@7351
   855
        *endp = (char *) string + len;
slouken@7351
   856
    }
slouken@7351
   857
    return value;
slouken@7351
   858
#endif /* HAVE_STRTOUL */
slouken@7351
   859
}
slouken@7351
   860
slouken@1895
   861
Sint64
slouken@1895
   862
SDL_strtoll(const char *string, char **endp, int base)
slouken@1330
   863
{
slouken@7351
   864
#if defined(HAVE_STRTOLL)
slouken@7352
   865
    return strtoll(string, endp, base);
slouken@7351
   866
#else
slouken@1330
   867
    size_t len;
slouken@11235
   868
    Sint64 value = 0;
slouken@1330
   869
slouken@1895
   870
    if (!base) {
slouken@1895
   871
        if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
slouken@1867
   872
            base = 16;
slouken@1867
   873
        } else {
slouken@1867
   874
            base = 10;
slouken@1867
   875
        }
slouken@1867
   876
    }
slouken@1867
   877
slouken@1867
   878
    len = SDL_ScanLongLong(string, base, &value);
slouken@1895
   879
    if (endp) {
slouken@1895
   880
        *endp = (char *) string + len;
slouken@1330
   881
    }
slouken@1330
   882
    return value;
slouken@7351
   883
#endif /* HAVE_STRTOLL */
slouken@1330
   884
}
slouken@1330
   885
slouken@1895
   886
Uint64
slouken@1895
   887
SDL_strtoull(const char *string, char **endp, int base)
slouken@1456
   888
{
slouken@7351
   889
#if defined(HAVE_STRTOULL)
slouken@7352
   890
    return strtoull(string, endp, base);
slouken@7351
   891
#else
slouken@1456
   892
    size_t len;
slouken@11235
   893
    Uint64 value = 0;
slouken@1456
   894
slouken@1895
   895
    if (!base) {
slouken@1895
   896
        if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
slouken@1867
   897
            base = 16;
slouken@1867
   898
        } else {
slouken@1867
   899
            base = 10;
slouken@1867
   900
        }
slouken@1867
   901
    }
slouken@1867
   902
slouken@1867
   903
    len = SDL_ScanUnsignedLongLong(string, base, &value);
slouken@1895
   904
    if (endp) {
slouken@1895
   905
        *endp = (char *) string + len;
slouken@1456
   906
    }
slouken@1456
   907
    return value;
slouken@7351
   908
#endif /* HAVE_STRTOULL */
slouken@1456
   909
}
slouken@1456
   910
slouken@1895
   911
double
slouken@1895
   912
SDL_strtod(const char *string, char **endp)
slouken@1341
   913
{
slouken@7351
   914
#if defined(HAVE_STRTOD)
slouken@7352
   915
    return strtod(string, endp);
slouken@7351
   916
#else
slouken@1341
   917
    size_t len;
slouken@11235
   918
    double value = 0.0;
slouken@1341
   919
slouken@1341
   920
    len = SDL_ScanFloat(string, &value);
slouken@1895
   921
    if (endp) {
slouken@1895
   922
        *endp = (char *) string + len;
slouken@1341
   923
    }
slouken@1341
   924
    return value;
slouken@7351
   925
#endif /* HAVE_STRTOD */
slouken@1341
   926
}
slouken@1341
   927
slouken@1895
   928
int
slouken@1895
   929
SDL_strcmp(const char *str1, const char *str2)
slouken@1330
   930
{
slouken@7351
   931
#if defined(HAVE_STRCMP)
slouken@7351
   932
    return strcmp(str1, str2);
slouken@7351
   933
#else
slouken@1330
   934
    while (*str1 && *str2) {
slouken@1895
   935
        if (*str1 != *str2)
slouken@1330
   936
            break;
slouken@1330
   937
        ++str1;
slouken@1330
   938
        ++str2;
slouken@1330
   939
    }
slouken@11265
   940
    return (int)((unsigned char) *str1 - (unsigned char) *str2);
slouken@7351
   941
#endif /* HAVE_STRCMP */
slouken@1330
   942
}
slouken@1330
   943
slouken@1895
   944
int
slouken@1895
   945
SDL_strncmp(const char *str1, const char *str2, size_t maxlen)
slouken@1330
   946
{
slouken@7351
   947
#if defined(HAVE_STRNCMP)
slouken@7351
   948
    return strncmp(str1, str2, maxlen);
slouken@7351
   949
#else
slouken@1895
   950
    while (*str1 && *str2 && maxlen) {
slouken@1895
   951
        if (*str1 != *str2)
slouken@1330
   952
            break;
slouken@1330
   953
        ++str1;
slouken@1330
   954
        ++str2;
slouken@1330
   955
        --maxlen;
slouken@1330
   956
    }
slouken@1895
   957
    if (!maxlen) {
slouken@1330
   958
        return 0;
slouken@1330
   959
    }
slouken@1895
   960
    return (int) ((unsigned char) *str1 - (unsigned char) *str2);
slouken@7351
   961
#endif /* HAVE_STRNCMP */
slouken@1330
   962
}
slouken@1330
   963
slouken@1895
   964
int
slouken@1895
   965
SDL_strcasecmp(const char *str1, const char *str2)
slouken@1330
   966
{
slouken@7351
   967
#ifdef HAVE_STRCASECMP
slouken@7351
   968
    return strcasecmp(str1, str2);
slouken@7351
   969
#elif defined(HAVE__STRICMP)
slouken@7351
   970
    return _stricmp(str1, str2);
slouken@7351
   971
#else
slouken@1330
   972
    char a = 0;
slouken@1330
   973
    char b = 0;
slouken@1895
   974
    while (*str1 && *str2) {
slouken@7351
   975
        a = SDL_toupper((unsigned char) *str1);
slouken@7351
   976
        b = SDL_toupper((unsigned char) *str2);
slouken@1895
   977
        if (a != b)
slouken@1330
   978
            break;
slouken@1330
   979
        ++str1;
slouken@1330
   980
        ++str2;
slouken@1330
   981
    }
slouken@7351
   982
    a = SDL_toupper(*str1);
slouken@7351
   983
    b = SDL_toupper(*str2);
slouken@1895
   984
    return (int) ((unsigned char) a - (unsigned char) b);
slouken@7351
   985
#endif /* HAVE_STRCASECMP */
slouken@1330
   986
}
slouken@1330
   987
slouken@1895
   988
int
slouken@1895
   989
SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen)
slouken@1501
   990
{
slouken@7351
   991
#ifdef HAVE_STRNCASECMP
slouken@7352
   992
    return strncasecmp(str1, str2, maxlen);
slouken@7351
   993
#elif defined(HAVE__STRNICMP)
slouken@7352
   994
    return _strnicmp(str1, str2, maxlen);
slouken@7351
   995
#else
slouken@1501
   996
    char a = 0;
slouken@1501
   997
    char b = 0;
slouken@1895
   998
    while (*str1 && *str2 && maxlen) {
icculus@2092
   999
        a = SDL_tolower((unsigned char) *str1);
icculus@2092
  1000
        b = SDL_tolower((unsigned char) *str2);
slouken@1895
  1001
        if (a != b)
slouken@1501
  1002
            break;
slouken@1501
  1003
        ++str1;
slouken@1501
  1004
        ++str2;
slouken@1501
  1005
        --maxlen;
slouken@1501
  1006
    }
slouken@6766
  1007
    if (maxlen == 0) {
slouken@6766
  1008
        return 0;
slouken@6766
  1009
    } else {
slouken@6766
  1010
        a = SDL_tolower((unsigned char) *str1);
slouken@6766
  1011
        b = SDL_tolower((unsigned char) *str2);
slouken@6766
  1012
        return (int) ((unsigned char) a - (unsigned char) b);
slouken@6766
  1013
    }
slouken@7351
  1014
#endif /* HAVE_STRNCASECMP */
slouken@1501
  1015
}
slouken@1501
  1016
icculus@7003
  1017
int
slouken@8820
  1018
SDL_sscanf(const char *text, SDL_SCANF_FORMAT_STRING const char *fmt, ...)
icculus@7003
  1019
{
icculus@7003
  1020
    int rc;
icculus@7003
  1021
    va_list ap;
icculus@7003
  1022
    va_start(ap, fmt);
icculus@8089
  1023
    rc = SDL_vsscanf(text, fmt, ap);
icculus@7003
  1024
    va_end(ap);
icculus@7003
  1025
    return rc;
icculus@7003
  1026
}
icculus@8089
  1027
icculus@8089
  1028
#ifdef HAVE_VSSCANF
icculus@8089
  1029
int
icculus@8089
  1030
SDL_vsscanf(const char *text, const char *fmt, va_list ap)
icculus@8089
  1031
{
icculus@8089
  1032
    return vsscanf(text, fmt, ap);
icculus@8089
  1033
}
icculus@7003
  1034
#else
slouken@1895
  1035
int
icculus@8092
  1036
SDL_vsscanf(const char *text, const char *fmt, va_list ap)
slouken@1330
  1037
{
slouken@1330
  1038
    int retval = 0;
slouken@1330
  1039
slouken@11227
  1040
    if (!text || !*text) {
slouken@11227
  1041
        return -1;
slouken@11227
  1042
    }
slouken@11227
  1043
slouken@1895
  1044
    while (*fmt) {
slouken@1895
  1045
        if (*fmt == ' ') {
icculus@2092
  1046
            while (SDL_isspace((unsigned char) *text)) {
slouken@1330
  1047
                ++text;
slouken@1330
  1048
            }
slouken@1330
  1049
            ++fmt;
slouken@1330
  1050
            continue;
slouken@1330
  1051
        }
slouken@1895
  1052
        if (*fmt == '%') {
slouken@1330
  1053
            SDL_bool done = SDL_FALSE;
slouken@1330
  1054
            long count = 0;
slouken@1330
  1055
            int radix = 10;
slouken@1895
  1056
            enum
slouken@1895
  1057
            {
slouken@1330
  1058
                DO_SHORT,
slouken@1330
  1059
                DO_INT,
slouken@1330
  1060
                DO_LONG,
slouken@1330
  1061
                DO_LONGLONG
slouken@1330
  1062
            } inttype = DO_INT;
slouken@11227
  1063
            size_t advance;
slouken@1330
  1064
            SDL_bool suppress = SDL_FALSE;
slouken@1330
  1065
slouken@1330
  1066
            ++fmt;
slouken@1895
  1067
            if (*fmt == '%') {
slouken@1895
  1068
                if (*text == '%') {
slouken@1330
  1069
                    ++text;
slouken@1330
  1070
                    ++fmt;
slouken@1330
  1071
                    continue;
slouken@1330
  1072
                }
slouken@1330
  1073
                break;
slouken@1330
  1074
            }
slouken@1895
  1075
            if (*fmt == '*') {
slouken@1330
  1076
                suppress = SDL_TRUE;
slouken@1330
  1077
                ++fmt;
slouken@1330
  1078
            }
slouken@1330
  1079
            fmt += SDL_ScanLong(fmt, 10, &count);
slouken@1330
  1080
slouken@1895
  1081
            if (*fmt == 'c') {
slouken@1895
  1082
                if (!count) {
slouken@1330
  1083
                    count = 1;
slouken@1330
  1084
                }
slouken@1895
  1085
                if (suppress) {
slouken@1895
  1086
                    while (count--) {
slouken@1330
  1087
                        ++text;
slouken@1330
  1088
                    }
slouken@1330
  1089
                } else {
slouken@1895
  1090
                    char *valuep = va_arg(ap, char *);
slouken@1895
  1091
                    while (count--) {
slouken@1330
  1092
                        *valuep++ = *text++;
slouken@1330
  1093
                    }
slouken@1330
  1094
                    ++retval;
slouken@1330
  1095
                }
slouken@1330
  1096
                continue;
slouken@1330
  1097
            }
slouken@1330
  1098
icculus@2092
  1099
            while (SDL_isspace((unsigned char) *text)) {
slouken@1330
  1100
                ++text;
slouken@1330
  1101
            }
slouken@1330
  1102
slouken@1330
  1103
            /* FIXME: implement more of the format specifiers */
slouken@1330
  1104
            while (!done) {
slouken@1895
  1105
                switch (*fmt) {
slouken@1895
  1106
                case '*':
slouken@1895
  1107
                    suppress = SDL_TRUE;
slouken@1895
  1108
                    break;
slouken@1895
  1109
                case 'h':
slouken@1895
  1110
                    if (inttype > DO_SHORT) {
slouken@1895
  1111
                        ++inttype;
slouken@1895
  1112
                    }
slouken@1895
  1113
                    break;
slouken@1895
  1114
                case 'l':
slouken@1895
  1115
                    if (inttype < DO_LONGLONG) {
slouken@1895
  1116
                        ++inttype;
slouken@1895
  1117
                    }
slouken@1895
  1118
                    break;
slouken@1895
  1119
                case 'I':
slouken@1895
  1120
                    if (SDL_strncmp(fmt, "I64", 3) == 0) {
slouken@1895
  1121
                        fmt += 2;
slouken@1895
  1122
                        inttype = DO_LONGLONG;
slouken@1895
  1123
                    }
slouken@1895
  1124
                    break;
slouken@1895
  1125
                case 'i':
slouken@1895
  1126
                    {
slouken@1895
  1127
                        int index = 0;
slouken@1895
  1128
                        if (text[index] == '-') {
slouken@1895
  1129
                            ++index;
slouken@1330
  1130
                        }
slouken@1895
  1131
                        if (text[index] == '0') {
slouken@7216
  1132
                            if (SDL_tolower((unsigned char) text[index + 1]) == 'x') {
slouken@1895
  1133
                                radix = 16;
slouken@1895
  1134
                            } else {
slouken@1895
  1135
                                radix = 8;
slouken@1895
  1136
                            }
slouken@1330
  1137
                        }
slouken@1895
  1138
                    }
slouken@1895
  1139
                    /* Fall through to %d handling */
slouken@1895
  1140
                case 'd':
slouken@1895
  1141
                    if (inttype == DO_LONGLONG) {
slouken@1895
  1142
                        Sint64 value;
slouken@11235
  1143
                        advance = SDL_ScanLongLong(text, radix, &value);
slouken@11235
  1144
                        text += advance;
slouken@11235
  1145
                        if (advance && !suppress) {
slouken@1895
  1146
                            Sint64 *valuep = va_arg(ap, Sint64 *);
slouken@1895
  1147
                            *valuep = value;
slouken@1895
  1148
                            ++retval;
slouken@1330
  1149
                        }
slouken@5512
  1150
                    } else {
slouken@1895
  1151
                        long value;
slouken@11227
  1152
                        advance = SDL_ScanLong(text, radix, &value);
slouken@11227
  1153
                        text += advance;
slouken@11227
  1154
                        if (advance && !suppress) {
slouken@1895
  1155
                            switch (inttype) {
slouken@1895
  1156
                            case DO_SHORT:
slouken@1895
  1157
                                {
slouken@1895
  1158
                                    short *valuep = va_arg(ap, short *);
slouken@1895
  1159
                                    *valuep = (short) value;
slouken@1895
  1160
                                }
slouken@1895
  1161
                                break;
slouken@1895
  1162
                            case DO_INT:
slouken@1895
  1163
                                {
slouken@1895
  1164
                                    int *valuep = va_arg(ap, int *);
slouken@1895
  1165
                                    *valuep = (int) value;
slouken@1895
  1166
                                }
slouken@1895
  1167
                                break;
slouken@1895
  1168
                            case DO_LONG:
slouken@1895
  1169
                                {
slouken@1895
  1170
                                    long *valuep = va_arg(ap, long *);
slouken@1895
  1171
                                    *valuep = value;
slouken@1895
  1172
                                }
slouken@1895
  1173
                                break;
slouken@1895
  1174
                            case DO_LONGLONG:
slouken@1895
  1175
                                /* Handled above */
slouken@1895
  1176
                                break;
slouken@1330
  1177
                            }
slouken@1895
  1178
                            ++retval;
slouken@1895
  1179
                        }
slouken@1895
  1180
                    }
slouken@1895
  1181
                    done = SDL_TRUE;
slouken@1895
  1182
                    break;
slouken@1895
  1183
                case 'o':
slouken@1895
  1184
                    if (radix == 10) {
slouken@1895
  1185
                        radix = 8;
slouken@1895
  1186
                    }
slouken@1895
  1187
                    /* Fall through to unsigned handling */
slouken@1895
  1188
                case 'x':
slouken@1895
  1189
                case 'X':
slouken@1895
  1190
                    if (radix == 10) {
slouken@1895
  1191
                        radix = 16;
slouken@1895
  1192
                    }
slouken@1895
  1193
                    /* Fall through to unsigned handling */
slouken@1895
  1194
                case 'u':
slouken@1895
  1195
                    if (inttype == DO_LONGLONG) {
slouken@11451
  1196
                        Uint64 value = 0;
slouken@11227
  1197
                        advance = SDL_ScanUnsignedLongLong(text, radix, &value);
slouken@11227
  1198
                        text += advance;
slouken@11227
  1199
                        if (advance && !suppress) {
slouken@1895
  1200
                            Uint64 *valuep = va_arg(ap, Uint64 *);
slouken@1895
  1201
                            *valuep = value;
slouken@1895
  1202
                            ++retval;
slouken@1895
  1203
                        }
slouken@5512
  1204
                    } else {
slouken@11451
  1205
                        unsigned long value = 0;
slouken@11227
  1206
                        advance = SDL_ScanUnsignedLong(text, radix, &value);
slouken@11227
  1207
                        text += advance;
slouken@11227
  1208
                        if (advance && !suppress) {
slouken@1895
  1209
                            switch (inttype) {
slouken@1895
  1210
                            case DO_SHORT:
slouken@1895
  1211
                                {
slouken@1895
  1212
                                    short *valuep = va_arg(ap, short *);
slouken@1895
  1213
                                    *valuep = (short) value;
slouken@1895
  1214
                                }
slouken@1895
  1215
                                break;
slouken@1895
  1216
                            case DO_INT:
slouken@1895
  1217
                                {
slouken@1895
  1218
                                    int *valuep = va_arg(ap, int *);
slouken@1895
  1219
                                    *valuep = (int) value;
slouken@1895
  1220
                                }
slouken@1895
  1221
                                break;
slouken@1895
  1222
                            case DO_LONG:
slouken@1895
  1223
                                {
slouken@1895
  1224
                                    long *valuep = va_arg(ap, long *);
slouken@1895
  1225
                                    *valuep = value;
slouken@1895
  1226
                                }
slouken@1895
  1227
                                break;
slouken@1895
  1228
                            case DO_LONGLONG:
slouken@1895
  1229
                                /* Handled above */
slouken@1895
  1230
                                break;
slouken@1895
  1231
                            }
slouken@1895
  1232
                            ++retval;
slouken@1895
  1233
                        }
slouken@1895
  1234
                    }
slouken@1895
  1235
                    done = SDL_TRUE;
slouken@1895
  1236
                    break;
slouken@1895
  1237
                case 'p':
slouken@1895
  1238
                    {
slouken@11451
  1239
                        uintptr_t value = 0;
slouken@11227
  1240
                        advance = SDL_ScanUintPtrT(text, 16, &value);
slouken@11227
  1241
                        text += advance;
slouken@11227
  1242
                        if (advance && !suppress) {
slouken@1895
  1243
                            void **valuep = va_arg(ap, void **);
slouken@1895
  1244
                            *valuep = (void *) value;
slouken@1895
  1245
                            ++retval;
slouken@1895
  1246
                        }
slouken@1895
  1247
                    }
slouken@1895
  1248
                    done = SDL_TRUE;
slouken@1895
  1249
                    break;
slouken@1895
  1250
                case 'f':
slouken@1895
  1251
                    {
slouken@1895
  1252
                        double value;
slouken@11227
  1253
                        advance = SDL_ScanFloat(text, &value);
slouken@11227
  1254
                        text += advance;
slouken@11227
  1255
                        if (advance && !suppress) {
slouken@1895
  1256
                            float *valuep = va_arg(ap, float *);
slouken@1895
  1257
                            *valuep = (float) value;
slouken@1895
  1258
                            ++retval;
slouken@1895
  1259
                        }
slouken@1895
  1260
                    }
slouken@1895
  1261
                    done = SDL_TRUE;
slouken@1895
  1262
                    break;
slouken@1895
  1263
                case 's':
slouken@1895
  1264
                    if (suppress) {
icculus@2092
  1265
                        while (!SDL_isspace((unsigned char) *text)) {
slouken@1895
  1266
                            ++text;
slouken@1895
  1267
                            if (count) {
slouken@1895
  1268
                                if (--count == 0) {
slouken@1895
  1269
                                    break;
slouken@1330
  1270
                                }
slouken@1330
  1271
                            }
slouken@1330
  1272
                        }
slouken@1895
  1273
                    } else {
slouken@1895
  1274
                        char *valuep = va_arg(ap, char *);
icculus@2092
  1275
                        while (!SDL_isspace((unsigned char) *text)) {
slouken@1895
  1276
                            *valuep++ = *text++;
slouken@1895
  1277
                            if (count) {
slouken@1895
  1278
                                if (--count == 0) {
slouken@1895
  1279
                                    break;
slouken@1895
  1280
                                }
slouken@1330
  1281
                            }
slouken@1330
  1282
                        }
slouken@1895
  1283
                        *valuep = '\0';
slouken@1895
  1284
                        ++retval;
slouken@1895
  1285
                    }
slouken@1895
  1286
                    done = SDL_TRUE;
slouken@1895
  1287
                    break;
slouken@1895
  1288
                default:
slouken@1895
  1289
                    done = SDL_TRUE;
slouken@1895
  1290
                    break;
slouken@1330
  1291
                }
slouken@1330
  1292
                ++fmt;
slouken@1330
  1293
            }
slouken@1330
  1294
            continue;
slouken@1330
  1295
        }
slouken@1895
  1296
        if (*text == *fmt) {
slouken@1330
  1297
            ++text;
slouken@1330
  1298
            ++fmt;
slouken@1330
  1299
            continue;
slouken@1330
  1300
        }
slouken@1330
  1301
        /* Text didn't match format specifier */
slouken@1330
  1302
        break;
slouken@1330
  1303
    }
slouken@1330
  1304
slouken@1330
  1305
    return retval;
slouken@1330
  1306
}
icculus@8089
  1307
#endif /* HAVE_VSSCANF */
slouken@1330
  1308
slouken@1895
  1309
int
slouken@8820
  1310
SDL_snprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
slouken@1330
  1311
{
slouken@1330
  1312
    va_list ap;
slouken@1330
  1313
    int retval;
slouken@1330
  1314
slouken@1330
  1315
    va_start(ap, fmt);
slouken@1330
  1316
    retval = SDL_vsnprintf(text, maxlen, fmt, ap);
slouken@1330
  1317
    va_end(ap);
slouken@1330
  1318
slouken@1330
  1319
    return retval;
slouken@1330
  1320
}
slouken@1330
  1321
slouken@7351
  1322
#ifdef HAVE_VSNPRINTF
slouken@8820
  1323
int SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap)
slouken@7351
  1324
{
slouken@8888
  1325
    if (!fmt) {
slouken@8888
  1326
        fmt = "";
slouken@8888
  1327
    }
slouken@7351
  1328
    return vsnprintf(text, maxlen, fmt, ap);
slouken@7351
  1329
}
icculus@7003
  1330
#else
slouken@7216
  1331
 /* FIXME: implement more of the format specifiers */
slouken@7728
  1332
typedef enum
slouken@7728
  1333
{
slouken@7728
  1334
    SDL_CASE_NOCHANGE,
slouken@7728
  1335
    SDL_CASE_LOWER,
slouken@7728
  1336
    SDL_CASE_UPPER
slouken@7728
  1337
} SDL_letter_case;
slouken@7728
  1338
slouken@7216
  1339
typedef struct
slouken@7216
  1340
{
slouken@7216
  1341
    SDL_bool left_justify;
slouken@7216
  1342
    SDL_bool force_sign;
slouken@7216
  1343
    SDL_bool force_type;
slouken@7216
  1344
    SDL_bool pad_zeroes;
slouken@7728
  1345
    SDL_letter_case force_case;
slouken@7216
  1346
    int width;
slouken@7216
  1347
    int radix;
slouken@7216
  1348
    int precision;
slouken@7216
  1349
} SDL_FormatInfo;
slouken@7216
  1350
slouken@1895
  1351
static size_t
slouken@7216
  1352
SDL_PrintString(char *text, size_t maxlen, SDL_FormatInfo *info, const char *string)
slouken@1330
  1353
{
slouken@7503
  1354
    size_t length = 0;
icculus@10460
  1355
    size_t slen;
slouken@7503
  1356
icculus@10887
  1357
    if (string == NULL) {
icculus@10887
  1358
        string = "(null)";
icculus@10887
  1359
    }
icculus@10887
  1360
slouken@7503
  1361
    if (info && info->width && (size_t)info->width > SDL_strlen(string)) {
slouken@7503
  1362
        char fill = info->pad_zeroes ? '0' : ' ';
slouken@7503
  1363
        size_t width = info->width - SDL_strlen(string);
slouken@7503
  1364
        while (width-- > 0 && maxlen > 0) {
slouken@7503
  1365
            *text++ = fill;
slouken@7503
  1366
            ++length;
slouken@7503
  1367
            --maxlen;
slouken@7503
  1368
        }
slouken@7503
  1369
    }
slouken@7503
  1370
icculus@10460
  1371
    slen = SDL_strlcpy(text, string, maxlen);
icculus@10460
  1372
    length += SDL_min(slen, maxlen);
slouken@7503
  1373
slouken@7728
  1374
    if (info) {
slouken@7728
  1375
        if (info->force_case == SDL_CASE_LOWER) {
slouken@7728
  1376
            SDL_strlwr(text);
slouken@7728
  1377
        } else if (info->force_case == SDL_CASE_UPPER) {
slouken@7728
  1378
            SDL_strupr(text);
slouken@7728
  1379
        }
slouken@7503
  1380
    }
slouken@7503
  1381
    return length;
slouken@1330
  1382
}
slouken@1895
  1383
slouken@1895
  1384
static size_t
slouken@7216
  1385
SDL_PrintLong(char *text, size_t maxlen, SDL_FormatInfo *info, long value)
slouken@1330
  1386
{
slouken@1330
  1387
    char num[130];
slouken@1330
  1388
slouken@7216
  1389
    SDL_ltoa(value, num, info ? info->radix : 10);
slouken@7216
  1390
    return SDL_PrintString(text, maxlen, info, num);
slouken@1330
  1391
}
slouken@1895
  1392
slouken@1895
  1393
static size_t
slouken@7216
  1394
SDL_PrintUnsignedLong(char *text, size_t maxlen, SDL_FormatInfo *info, unsigned long value)
slouken@1330
  1395
{
slouken@1330
  1396
    char num[130];
slouken@1330
  1397
slouken@7216
  1398
    SDL_ultoa(value, num, info ? info->radix : 10);
slouken@7216
  1399
    return SDL_PrintString(text, maxlen, info, num);
slouken@1330
  1400
}
slouken@1895
  1401
slouken@1895
  1402
static size_t
slouken@7216
  1403
SDL_PrintLongLong(char *text, size_t maxlen, SDL_FormatInfo *info, Sint64 value)
slouken@1330
  1404
{
slouken@1330
  1405
    char num[130];
slouken@1330
  1406
slouken@7216
  1407
    SDL_lltoa(value, num, info ? info->radix : 10);
slouken@7216
  1408
    return SDL_PrintString(text, maxlen, info, num);
slouken@1330
  1409
}
slouken@5512
  1410
slouken@1895
  1411
static size_t
slouken@7216
  1412
SDL_PrintUnsignedLongLong(char *text, size_t maxlen, SDL_FormatInfo *info, Uint64 value)
slouken@1330
  1413
{
slouken@7216
  1414
    char num[130];
slouken@7216
  1415
slouken@7216
  1416
    SDL_ulltoa(value, num, info ? info->radix : 10);
slouken@7216
  1417
    return SDL_PrintString(text, maxlen, info, num);
slouken@7216
  1418
}
slouken@7216
  1419
slouken@7216
  1420
static size_t
slouken@7216
  1421
SDL_PrintFloat(char *text, size_t maxlen, SDL_FormatInfo *info, double arg)
slouken@7216
  1422
{
icculus@7482
  1423
    int width;
slouken@7217
  1424
    size_t len;
slouken@7216
  1425
    size_t left = maxlen;
slouken@1330
  1426
    char *textstart = text;
slouken@7216
  1427
slouken@1895
  1428
    if (arg) {
slouken@1330
  1429
        /* This isn't especially accurate, but hey, it's easy. :) */
slouken@1330
  1430
        unsigned long value;
slouken@1330
  1431
slouken@1895
  1432
        if (arg < 0) {
slouken@7216
  1433
            if (left > 1) {
slouken@7216
  1434
                *text = '-';
slouken@7216
  1435
                --left;
slouken@7216
  1436
            }
slouken@7216
  1437
            ++text;
slouken@1330
  1438
            arg = -arg;
slouken@7216
  1439
        } else if (info->force_sign) {
slouken@7216
  1440
            if (left > 1) {
slouken@7216
  1441
                *text = '+';
slouken@7216
  1442
                --left;
slouken@7216
  1443
            }
slouken@7216
  1444
            ++text;
slouken@1330
  1445
        }
slouken@1895
  1446
        value = (unsigned long) arg;
slouken@7216
  1447
        len = SDL_PrintUnsignedLong(text, left, NULL, value);
slouken@7216
  1448
        if (len >= left) {
icculus@10460
  1449
            text += (left > 1) ? left - 1 : 0;
slouken@7216
  1450
            left = SDL_min(left, 1);
slouken@7216
  1451
        } else {
icculus@10460
  1452
            text += len;
slouken@7216
  1453
            left -= len;
slouken@7216
  1454
        }
slouken@1330
  1455
        arg -= value;
slouken@7216
  1456
        if (info->precision < 0) {
slouken@7216
  1457
            info->precision = 6;
slouken@7216
  1458
        }
slouken@7216
  1459
        if (info->force_type || info->precision > 0) {
slouken@1330
  1460
            int mult = 10;
slouken@7216
  1461
            if (left > 1) {
slouken@7216
  1462
                *text = '.';
slouken@7216
  1463
                --left;
slouken@7216
  1464
            }
slouken@7216
  1465
            ++text;
slouken@7216
  1466
            while (info->precision-- > 0) {
slouken@1895
  1467
                value = (unsigned long) (arg * mult);
slouken@7216
  1468
                len = SDL_PrintUnsignedLong(text, left, NULL, value);
slouken@7216
  1469
                if (len >= left) {
icculus@10460
  1470
                    text += (left > 1) ? left - 1 : 0;
slouken@7216
  1471
                    left = SDL_min(left, 1);
slouken@7216
  1472
                } else {
icculus@10460
  1473
                    text += len;
slouken@7216
  1474
                    left -= len;
slouken@7216
  1475
                }
slouken@1895
  1476
                arg -= (double) value / mult;
slouken@1330
  1477
                mult *= 10;
slouken@1330
  1478
            }
slouken@1330
  1479
        }
slouken@1330
  1480
    } else {
slouken@7216
  1481
        if (left > 1) {
slouken@7216
  1482
            *text = '0';
slouken@7216
  1483
            --left;
slouken@7216
  1484
        }
slouken@7216
  1485
        ++text;
slouken@7216
  1486
        if (info->force_type) {
slouken@7216
  1487
            if (left > 1) {
slouken@7216
  1488
                *text = '.';
slouken@7216
  1489
                --left;
slouken@7216
  1490
            }
slouken@7216
  1491
            ++text;
slouken@7216
  1492
        }
slouken@1330
  1493
    }
slouken@1895
  1494
slouken@7216
  1495
    width = info->width - (int)(text - textstart);
slouken@7216
  1496
    if (width > 0) {
slouken@7216
  1497
        char fill = info->pad_zeroes ? '0' : ' ';
slouken@7216
  1498
        char *end = text+left-1;
slouken@7216
  1499
        len = (text - textstart);
slouken@7216
  1500
        for (len = (text - textstart); len--; ) {
slouken@7216
  1501
            if ((textstart+len+width) < end) {
slouken@7216
  1502
                *(textstart+len+width) = *(textstart+len);
slouken@7216
  1503
            }
slouken@7216
  1504
        }
slouken@7216
  1505
        len = (size_t)width;
slouken@7216
  1506
        if (len >= left) {
icculus@10460
  1507
            text += (left > 1) ? left - 1 : 0;
slouken@7216
  1508
            left = SDL_min(left, 1);
slouken@7216
  1509
        } else {
icculus@10460
  1510
            text += len;
slouken@7216
  1511
            left -= len;
slouken@7216
  1512
        }
slouken@7216
  1513
        while (len--) {
slouken@7216
  1514
            if (textstart+len < end) {
slouken@7216
  1515
                textstart[len] = fill;
slouken@7216
  1516
            }
slouken@7216
  1517
        }
slouken@1330
  1518
    }
slouken@7216
  1519
slouken@1330
  1520
    return (text - textstart);
slouken@1330
  1521
}
slouken@1895
  1522
slouken@1895
  1523
int
slouken@8820
  1524
SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap)
slouken@1330
  1525
{
slouken@7216
  1526
    size_t left = maxlen;
slouken@1330
  1527
    char *textstart = text;
slouken@7216
  1528
slouken@8839
  1529
    if (!fmt) {
slouken@8839
  1530
        fmt = "";
slouken@8839
  1531
    }
slouken@10733
  1532
    while (*fmt && left > 1) {
slouken@1895
  1533
        if (*fmt == '%') {
slouken@1330
  1534
            SDL_bool done = SDL_FALSE;
slouken@1330
  1535
            size_t len = 0;
slouken@7216
  1536
            SDL_bool check_flag;
slouken@7216
  1537
            SDL_FormatInfo info;
slouken@1895
  1538
            enum
slouken@1895
  1539
            {
slouken@1330
  1540
                DO_INT,
slouken@1330
  1541
                DO_LONG,
slouken@1330
  1542
                DO_LONGLONG
slouken@1330
  1543
            } inttype = DO_INT;
slouken@1330
  1544
slouken@7216
  1545
            SDL_zero(info);
slouken@7216
  1546
            info.radix = 10;
slouken@7216
  1547
            info.precision = -1;
slouken@7216
  1548
slouken@7216
  1549
            check_flag = SDL_TRUE;
slouken@7216
  1550
            while (check_flag) {
slouken@1818
  1551
                ++fmt;
slouken@7216
  1552
                switch (*fmt) {
slouken@7216
  1553
                case '-':
slouken@7216
  1554
                    info.left_justify = SDL_TRUE;
slouken@7216
  1555
                    break;
slouken@7216
  1556
                case '+':
slouken@7216
  1557
                    info.force_sign = SDL_TRUE;
slouken@7216
  1558
                    break;
slouken@7216
  1559
                case '#':
slouken@7216
  1560
                    info.force_type = SDL_TRUE;
slouken@7216
  1561
                    break;
slouken@7216
  1562
                case '0':
slouken@7216
  1563
                    info.pad_zeroes = SDL_TRUE;
slouken@7216
  1564
                    break;
slouken@7216
  1565
                default:
slouken@7216
  1566
                    check_flag = SDL_FALSE;
slouken@7216
  1567
                    break;
slouken@7216
  1568
                }
slouken@1818
  1569
            }
slouken@7216
  1570
slouken@7216
  1571
            if (*fmt >= '0' && *fmt <= '9') {
slouken@7216
  1572
                info.width = SDL_strtol(fmt, (char **)&fmt, 0);
slouken@7216
  1573
            }
slouken@7216
  1574
slouken@7216
  1575
            if (*fmt == '.') {
slouken@7216
  1576
                ++fmt;
slouken@7216
  1577
                if (*fmt >= '0' && *fmt <= '9') {
slouken@7216
  1578
                    info.precision = SDL_strtol(fmt, (char **)&fmt, 0);
slouken@7216
  1579
                } else {
slouken@7216
  1580
                    info.precision = 0;
slouken@7216
  1581
                }
slouken@7216
  1582
            }
slouken@7216
  1583
slouken@1330
  1584
            while (!done) {
slouken@1895
  1585
                switch (*fmt) {
slouken@1895
  1586
                case '%':
slouken@7216
  1587
                    if (left > 1) {
slouken@7216
  1588
                        *text = '%';
slouken@7216
  1589
                    }
slouken@1895
  1590
                    len = 1;
slouken@1895
  1591
                    done = SDL_TRUE;
slouken@1895
  1592
                    break;
slouken@1895
  1593
                case 'c':
slouken@1895
  1594
                    /* char is promoted to int when passed through (...) */
slouken@7216
  1595
                    if (left > 1) {
slouken@7216
  1596
                        *text = (char) va_arg(ap, int);
slouken@7216
  1597
                    }
slouken@1895
  1598
                    len = 1;
slouken@1895
  1599
                    done = SDL_TRUE;
slouken@1895
  1600
                    break;
slouken@1895
  1601
                case 'h':
slouken@1895
  1602
                    /* short is promoted to int when passed through (...) */
slouken@1895
  1603
                    break;
slouken@1895
  1604
                case 'l':
slouken@1895
  1605
                    if (inttype < DO_LONGLONG) {
slouken@1895
  1606
                        ++inttype;
slouken@1895
  1607
                    }
slouken@1895
  1608
                    break;
slouken@1895
  1609
                case 'I':
slouken@1895
  1610
                    if (SDL_strncmp(fmt, "I64", 3) == 0) {
slouken@1895
  1611
                        fmt += 2;
slouken@1895
  1612
                        inttype = DO_LONGLONG;
slouken@1895
  1613
                    }
slouken@1895
  1614
                    break;
slouken@1895
  1615
                case 'i':
slouken@1895
  1616
                case 'd':
slouken@1895
  1617
                    switch (inttype) {
slouken@1895
  1618
                    case DO_INT:
slouken@7216
  1619
                        len = SDL_PrintLong(text, left, &info,
slouken@7216
  1620
                                            (long) va_arg(ap, int));
slouken@1330
  1621
                        break;
slouken@1895
  1622
                    case DO_LONG:
slouken@7216
  1623
                        len = SDL_PrintLong(text, left, &info,
slouken@7216
  1624
                                            va_arg(ap, long));
slouken@1330
  1625
                        break;
slouken@1895
  1626
                    case DO_LONGLONG:
slouken@7216
  1627
                        len = SDL_PrintLongLong(text, left, &info,
slouken@7216
  1628
                                                va_arg(ap, Sint64));
slouken@1330
  1629
                        break;
slouken@1895
  1630
                    }
slouken@1895
  1631
                    done = SDL_TRUE;
slouken@1895
  1632
                    break;
slouken@1895
  1633
                case 'p':
slouken@1895
  1634
                case 'x':
slouken@7728
  1635
                    info.force_case = SDL_CASE_LOWER;
slouken@1895
  1636
                    /* Fall through to 'X' handling */
slouken@1895
  1637
                case 'X':
slouken@7728
  1638
                    if (info.force_case == SDL_CASE_NOCHANGE) {
slouken@7728
  1639
                        info.force_case = SDL_CASE_UPPER;
slouken@7728
  1640
                    }
slouken@7216
  1641
                    if (info.radix == 10) {
slouken@7216
  1642
                        info.radix = 16;
slouken@1895
  1643
                    }
slouken@1895
  1644
                    if (*fmt == 'p') {
slouken@1895
  1645
                        inttype = DO_LONG;
slouken@1895
  1646
                    }
slouken@1895
  1647
                    /* Fall through to unsigned handling */
slouken@1895
  1648
                case 'o':
slouken@7216
  1649
                    if (info.radix == 10) {
slouken@7216
  1650
                        info.radix = 8;
slouken@1895
  1651
                    }
slouken@1895
  1652
                    /* Fall through to unsigned handling */
slouken@1895
  1653
                case 'u':
slouken@7503
  1654
                    info.pad_zeroes = SDL_TRUE;
slouken@1895
  1655
                    switch (inttype) {
slouken@1895
  1656
                    case DO_INT:
slouken@7216
  1657
                        len = SDL_PrintUnsignedLong(text, left, &info,
slouken@7216
  1658
                                                    (unsigned long)
slouken@7216
  1659
                                                    va_arg(ap, unsigned int));
slouken@1330
  1660
                        break;
slouken@1895
  1661
                    case DO_LONG:
slouken@7216
  1662
                        len = SDL_PrintUnsignedLong(text, left, &info,
slouken@7216
  1663
                                                    va_arg(ap, unsigned long));
slouken@1330
  1664
                        break;
slouken@1895
  1665
                    case DO_LONGLONG:
slouken@7216
  1666
                        len = SDL_PrintUnsignedLongLong(text, left, &info,
slouken@7216
  1667
                                                        va_arg(ap, Uint64));
slouken@1330
  1668
                        break;
slouken@1895
  1669
                    }
slouken@1895
  1670
                    done = SDL_TRUE;
slouken@1895
  1671
                    break;
slouken@1895
  1672
                case 'f':
slouken@7216
  1673
                    len = SDL_PrintFloat(text, left, &info, va_arg(ap, double));
slouken@1895
  1674
                    done = SDL_TRUE;
slouken@1895
  1675
                    break;
slouken@10818
  1676
                case 'S':
slouken@10818
  1677
                    {
slouken@10818
  1678
                        /* In practice this is used on Windows for WCHAR strings */
slouken@10818
  1679
                        wchar_t *wide_arg = va_arg(ap, wchar_t *);
slouken@10818
  1680
                        char *arg = SDL_iconv_string("UTF-8", "UTF-16LE", (char *)(wide_arg), (SDL_wcslen(wide_arg)+1)*sizeof(*wide_arg));
slouken@10818
  1681
                        len = SDL_PrintString(text, left, &info, arg);
slouken@10818
  1682
                        SDL_free(arg);
slouken@10818
  1683
                        done = SDL_TRUE;
slouken@10818
  1684
                    }
slouken@10818
  1685
                    break;
slouken@1895
  1686
                case 's':
slouken@7216
  1687
                    len = SDL_PrintString(text, left, &info, va_arg(ap, char *));
slouken@1895
  1688
                    done = SDL_TRUE;
slouken@1895
  1689
                    break;
slouken@1895
  1690
                default:
slouken@1895
  1691
                    done = SDL_TRUE;
slouken@1895
  1692
                    break;
slouken@1330
  1693
                }
slouken@1330
  1694
                ++fmt;
slouken@1330
  1695
            }
slouken@7216
  1696
            if (len >= left) {
icculus@10460
  1697
                text += (left > 1) ? left - 1 : 0;
slouken@7216
  1698
                left = SDL_min(left, 1);
slouken@7216
  1699
            } else {
icculus@10460
  1700
                text += len;
slouken@7216
  1701
                left -= len;
slouken@7216
  1702
            }
slouken@1330
  1703
        } else {
slouken@10733
  1704
            *text++ = *fmt++;
slouken@10733
  1705
            --left;
slouken@1330
  1706
        }
slouken@1330
  1707
    }
slouken@7216
  1708
    if (left > 0) {
slouken@7216
  1709
        *text = '\0';
slouken@7216
  1710
    }
slouken@3253
  1711
    return (int)(text - textstart);
slouken@1330
  1712
}
slouken@7351
  1713
#endif /* HAVE_VSNPRINTF */
icculus@7003
  1714
slouken@1895
  1715
/* vi: set ts=4 sw=4 expandtab: */