Subversion Repositories eduke32

Rev

Rev 5005 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
99 terminx 1
/*
2
 * Playing-field leveller for Build
3
 * by Jonathon Fowler
4
 *
5
 * A note about this:
6
 * 1. There is some kind of problem somewhere in the functions below because
7
 *    compiling with __compat_h_macrodef__ disabled makes stupid things happen.
8
 * 2. The functions below, aside from the ones which aren't trivial, were never
9
 *    really intended to be used for anything except tracking anr removing ties
10
 *    to the standard C library from games. Using the Bxx versions of functions
11
 *    means we can redefine those names to link up with different runtime library
12
 *    names.
13
 */
14
 
4761 hendricks2 15
#include "compat.h"
16
 
99 terminx 17
#ifdef _WIN32
4761 hendricks2 18
# include <shlobj.h>
19
# include <direct.h>
4801 hendricks2 20
#elif __APPLE__
21
# include "osxbits.h"
99 terminx 22
#endif
23
 
1454 terminx 24
#if defined(_MSC_VER)
99 terminx 25
# include <io.h>
26
#else
27
# include <dirent.h>
28
#endif
29
 
5037 hendricks2 30
#if defined __linux || defined EDUKE32_BSD
4801 hendricks2 31
# include <libgen.h> // for dirname()
32
#endif
5037 hendricks2 33
#if defined __FreeBSD__
34
# include <limits.h> // for PATH_MAX
4801 hendricks2 35
# include <sys/sysctl.h> // for sysctl() to get path to executable
36
#endif
37
 
1586 terminx 38
#include "baselayer.h"
99 terminx 39
 
4490 helixhorne 40
////////// PANICKING ALLOCATION FUNCTIONS //////////
41
 
42
static void (*g_MemErrHandler)(int32_t line, const char *file, const char *func);
43
 
44
#ifdef DEBUGGINGAIDS
45
static const char *g_MemErrFunc = "???";
46
static const char *g_MemErrFile = "???";
47
static int32_t g_MemErrLine;
48
 
49
void xalloc_set_location(int32_t line, const char *file, const char *func)
50
{
51
    g_MemErrLine = line;
52
    g_MemErrFile = file;
53
 
54
    if (func)
55
        g_MemErrFunc = func;
56
}
57
#endif
58
 
4619 terminx 59
void handle_memerr(void)
4490 helixhorne 60
{
4619 terminx 61
    if (g_MemErrHandler)
4490 helixhorne 62
    {
63
#ifdef DEBUGGINGAIDS
4619 terminx 64
        g_MemErrHandler(g_MemErrLine, g_MemErrFile, g_MemErrFunc);
4490 helixhorne 65
#else
4619 terminx 66
        g_MemErrHandler(0, "???", "???");
4490 helixhorne 67
#endif
4619 terminx 68
    }
4490 helixhorne 69
 
4619 terminx 70
    Bexit(EXIT_FAILURE);
4490 helixhorne 71
}
72
 
4619 terminx 73
void set_memerr_handler(void(*handlerfunc)(int32_t, const char *, const char *))
4490 helixhorne 74
{
75
    g_MemErrHandler = handlerfunc;
76
}
77
 
78
//////////
79
 
4747 terminx 80
#ifndef compat_h_macrodef__
99 terminx 81
 
4894 terminx 82
void Bassert(int expr) { assert(expr); }
83
int32_t Brand(void) { return rand(); }
84
void *Bmalloc(bsize_t size) { return malloc(size); }
85
void Bfree(void *ptr) { Bfree(ptr); }
2546 helixhorne 86
 
1399 terminx 87
int32_t Bopen(const char *pathname, int32_t flags, uint32_t mode)
99 terminx 88
{
4894 terminx 89
    int32_t n = 0, o = 0;
109 terminx 90
 
4894 terminx 91
    if (flags & BO_BINARY)
92
        n |= O_BINARY;
93
    else
94
        n |= O_TEXT;
95
    if ((flags & BO_RDWR) == BO_RDWR)
96
        n |= O_RDWR;
97
    else if ((flags & BO_RDWR) == BO_WRONLY)
98
        n |= O_WRONLY;
99
    else if ((flags & BO_RDWR) == BO_RDONLY)
100
        n |= O_RDONLY;
101
    if (flags & BO_APPEND)
102
        n |= O_APPEND;
103
    if (flags & BO_CREAT)
104
        n |= O_CREAT;
105
    if (flags & BO_TRUNC)
106
        n |= O_TRUNC;
107
    if (mode & BS_IREAD)
108
        o |= S_IREAD;
109
    if (mode & BS_IWRITE)
110
        o |= S_IWRITE;
111
    if (mode & BS_IEXEC)
112
        o |= S_IEXEC;
109 terminx 113
 
4894 terminx 114
    return open(pathname, n, o);
99 terminx 115
}
116
 
4894 terminx 117
int32_t Bclose(int32_t fd) { return close(fd); }
118
bssize_t Bwrite(int32_t fd, const void *buf, bsize_t count) { return write(fd, buf, count); }
119
bssize_t Bread(int32_t fd, void *buf, bsize_t count) { return read(fd, buf, count); }
99 terminx 120
 
1205 terminx 121
int32_t Blseek(int32_t fildes, int32_t offset, int32_t whence)
99 terminx 122
{
584 terminx 123
    switch (whence)
124
    {
4894 terminx 125
        case BSEEK_SET: whence = SEEK_SET; break;
126
        case BSEEK_CUR: whence = SEEK_CUR; break;
127
        case BSEEK_END: whence = SEEK_END; break;
109 terminx 128
    }
4894 terminx 129
    return lseek(fildes, offset, whence);
99 terminx 130
}
131
 
4894 terminx 132
BFILE *Bfopen(const char *path, const char *mode) { return (BFILE *)fopen(path, mode); }
133
int32_t Bfclose(BFILE *stream) { return fclose((FILE *)stream); }
134
void Brewind(BFILE *stream) { rewind((FILE *)stream); }
135
int32_t Bfgetc(BFILE *stream) { return fgetc((FILE *)stream); }
136
char *Bfgets(char *s, int32_t size, BFILE *stream) { return fgets(s, size, (FILE *)stream); }
137
int32_t Bfputc(int32_t c, BFILE *stream) { return fputc(c, (FILE *)stream); }
138
int32_t Bfputs(const char *s, BFILE *stream) { return fputs(s, (FILE *)stream); }
139
bsize_t Bfread(void *ptr, bsize_t size, bsize_t nmemb, BFILE *stream) { return fread(ptr, size, nmemb, (FILE *)stream); }
140
bsize_t Bfwrite(const void *ptr, bsize_t size, bsize_t nmemb, BFILE *stream) { return fwrite(ptr, size, nmemb, (FILE *)stream); }
141
char *Bstrdup(const char *s) { return strdup(s); }
142
char *Bstrcpy(char *dest, const char *src) { return strcpy(dest, src); }
143
char *Bstrncpy(char *dest, const char *src, bsize_t n) { return Bstrncpy(dest, src, n); }
144
int32_t Bstrcmp(const char *s1, const char *s2) { return strcmp(s1, s2); }
145
int32_t Bstrncmp(const char *s1, const char *s2, bsize_t n) { return strncmp(s1, s2, n); }
99 terminx 146
 
1205 terminx 147
int32_t Bstrcasecmp(const char *s1, const char *s2)
99 terminx 148
{
149
#ifdef _MSC_VER
4894 terminx 150
    return _stricmp(s1, s2);
99 terminx 151
#else
4894 terminx 152
    return strcasecmp(s1, s2);
99 terminx 153
#endif
154
}
155
 
1205 terminx 156
int32_t Bstrncasecmp(const char *s1, const char *s2, bsize_t n)
99 terminx 157
{
158
#ifdef _MSC_VER
4894 terminx 159
    return _strnicmp(s1, s2, n);
99 terminx 160
#else
4894 terminx 161
    return strncasecmp(s1, s2, n);
99 terminx 162
#endif
163
}
164
 
4894 terminx 165
char *Bstrcat(char *dest, const char *src) { return strcat(dest, src); }
166
char *Bstrncat(char *dest, const char *src, bsize_t n) { return strncat(dest, src, n); }
167
bsize_t Bstrlen(const char *s) { return strlen(s); }
168
char *Bstrchr(const char *s, int32_t c) { return strchr(s, c); }
169
char *Bstrrchr(const char *s, int32_t c) { return strrchr(s, c); }
170
int32_t Batoi(const char *nptr) { return strtol(nptr, NULL, 10); }
171
int32_t Batol(const char *nptr) { return strtol(nptr, NULL, 10); }
172
int32_t Bstrtol(const char *nptr, char **endptr, int32_t base) { return strtol(nptr, endptr, base); }
173
uint32_t Bstrtoul(const char *nptr, char **endptr, int32_t base) { return strtoul(nptr, endptr, base); }
174
void *Bmemcpy(void *dest, const void *src, bsize_t n) { return memcpy(dest, src, n); }
175
void *Bmemmove(void *dest, const void *src, bsize_t n) { return memmove(dest, src, n); }
176
void *Bmemchr(const void *s, int32_t c, bsize_t n) { return memchr(s, c, n); }
177
void *Bmemset(void *s, int32_t c, bsize_t n) { return memset(s, c, n); }
99 terminx 178
 
1205 terminx 179
int32_t Bprintf(const char *format, ...)
99 terminx 180
{
109 terminx 181
    va_list ap;
1205 terminx 182
    int32_t r;
99 terminx 183
 
4894 terminx 184
    va_start(ap, format);
99 terminx 185
#ifdef _MSC_VER
4894 terminx 186
    r = _vprintf(format, ap);
99 terminx 187
#else
4894 terminx 188
    r = vprintf(format, ap);
99 terminx 189
#endif
109 terminx 190
    va_end(ap);
191
    return r;
99 terminx 192
}
193
 
1205 terminx 194
int32_t Bsprintf(char *str, const char *format, ...)
99 terminx 195
{
109 terminx 196
    va_list ap;
1205 terminx 197
    int32_t r;
99 terminx 198
 
4894 terminx 199
    va_start(ap, format);
99 terminx 200
#ifdef _MSC_VER
4894 terminx 201
    r = _vsprintf(str, format, ap);
99 terminx 202
#else
4894 terminx 203
    r = vsprintf(str, format, ap);
99 terminx 204
#endif
109 terminx 205
    va_end(ap);
206
    return r;
99 terminx 207
}
208
 
1205 terminx 209
int32_t Bsnprintf(char *str, bsize_t size, const char *format, ...)
99 terminx 210
{
109 terminx 211
    va_list ap;
1205 terminx 212
    int32_t r;
99 terminx 213
 
4894 terminx 214
    va_start(ap, format);
99 terminx 215
#ifdef _MSC_VER
4894 terminx 216
    r = _vsnprintf(str, size, format, ap);
99 terminx 217
#else
4894 terminx 218
    r = vsnprintf(str, size, format, ap);
99 terminx 219
#endif
109 terminx 220
    va_end(ap);
221
    return r;
99 terminx 222
}
223
 
1205 terminx 224
int32_t Bvsnprintf(char *str, bsize_t size, const char *format, va_list ap)
99 terminx 225
{
226
#ifdef _MSC_VER
4894 terminx 227
    return _vsnprintf(str, size, format, ap);
99 terminx 228
#else
4894 terminx 229
    return vsnprintf(str, size, format, ap);
99 terminx 230
#endif
231
}
232
 
4894 terminx 233
char *Bgetenv(const char *name) { return getenv(name); }
234
char *Bgetcwd(char *buf, bsize_t size) { return getcwd(buf, size); }
99 terminx 235
 
236
#endif  // __compat_h_macrodef__
237
 
238
 
239
//
240
// Stuff which must be a function
241
//
3116 hendricks2 242
#ifdef _WIN32
243
typedef BOOL (WINAPI * aSHGetSpecialFolderPathAtype)(HWND, LPTSTR, int, BOOL);
244
#endif
99 terminx 245
 
246
char *Bgethomedir(void)
247
{
248
#ifdef _WIN32
3116 hendricks2 249
    aSHGetSpecialFolderPathAtype aSHGetSpecialFolderPathA;
109 terminx 250
    TCHAR appdata[MAX_PATH];
1205 terminx 251
    int32_t loaded = 0;
1003 terminx 252
    HMODULE hShell32 = GetModuleHandle("shell32.dll");
99 terminx 253
 
1003 terminx 254
    if (hShell32 == NULL)
255
    {
256
        hShell32 = LoadLibrary("shell32.dll");
257
        loaded = 1;
258
    }
259
 
260
    if (hShell32 == NULL)
261
        return NULL;
262
 
3116 hendricks2 263
    aSHGetSpecialFolderPathA = (aSHGetSpecialFolderPathAtype)GetProcAddress(hShell32, "SHGetSpecialFolderPathA");
632 terminx 264
    if (aSHGetSpecialFolderPathA != NULL)
265
        if (SUCCEEDED(aSHGetSpecialFolderPathA(NULL, appdata, CSIDL_APPDATA, FALSE)))
1003 terminx 266
        {
267
            if (loaded)
268
                FreeLibrary(hShell32);
1527 terminx 269
            return Bstrdup(appdata);
1003 terminx 270
        }
271
 
272
    if (loaded)
273
        FreeLibrary(hShell32);
109 terminx 274
    return NULL;
5005 hendricks2 275
#elif defined EDUKE32_OSX
4801 hendricks2 276
    return osx_gethomedir();
2628 helixhorne 277
#elif defined(GEKKO)
278
    // return current drive's name
279
    char *drv, cwd[BMAX_PATH] = {0};
280
    getcwd(cwd, BMAX_PATH);
281
    drv = strchr(cwd, ':');
282
    if (drv)
283
        drv[1] = '\0';
284
    return Bstrdup(cwd);
99 terminx 285
#else
109 terminx 286
    char *e = getenv("HOME");
287
    if (!e) return NULL;
1527 terminx 288
    return Bstrdup(e);
99 terminx 289
#endif
290
}
291
 
4801 hendricks2 292
char *Bgetappdir(void)
293
{
294
    char *dir = NULL;
4802 hendricks2 295
 
4801 hendricks2 296
#ifdef _WIN32
297
        TCHAR appdir[MAX_PATH];
4802 hendricks2 298
 
4801 hendricks2 299
        if (GetModuleFileName(NULL, appdir, MAX_PATH) > 0) {
300
                // trim off the filename
4894 terminx 301
                char *slash = Bstrrchr(appdir, '\\');
4801 hendricks2 302
                if (slash) slash[0] = 0;
4894 terminx 303
                dir = Bstrdup(appdir);
4801 hendricks2 304
    }
305
 
5005 hendricks2 306
#elif defined EDUKE32_OSX
4801 hendricks2 307
    dir = osx_getappdir();
5037 hendricks2 308
#elif defined __FreeBSD__
309
    // the sysctl should also work when /proc/ is not mounted (which seems to
310
    // be common on FreeBSD), so use it..
4801 hendricks2 311
    char buf[PATH_MAX] = {0};
5037 hendricks2 312
    int name[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
313
    size_t len = sizeof(buf)-1;
314
    int ret = sysctl(name, sizeof(name)/sizeof(name[0]), buf, &len, NULL, 0);
315
    if(ret == 0 && buf[0] != '\0') {
316
        // again, remove executable name with dirname()
317
        // on FreeBSD dirname() seems to use some internal buffer
318
        dir = strdup(dirname(buf));
319
    }
320
#elif defined __linux || defined EDUKE32_BSD
321
    char buf[PATH_MAX] = {0};
4801 hendricks2 322
    char buf2[PATH_MAX] = {0};
323
#  ifdef __linux
4894 terminx 324
    Bsnprintf(buf, sizeof(buf), "/proc/%d/exe", getpid());
4801 hendricks2 325
#  else // the BSDs.. except for FreeBSD which has a sysctl
4894 terminx 326
    Bsnprintf(buf, sizeof(buf), "/proc/%d/file", getpid());
4801 hendricks2 327
#  endif
328
    int len = readlink(buf, buf2, sizeof(buf2));
329
    if (len != -1) {
330
        // remove executable name with dirname(3)
331
        // on Linux, dirname() will modify buf2 (cutting off executable name) and return it
332
        // on FreeBSD it seems to use some internal buffer instead.. anyway, just strdup()
4894 terminx 333
        dir = Bstrdup(dirname(buf2));
4801 hendricks2 334
    }
194 terminx 335
#endif
4802 hendricks2 336
 
4801 hendricks2 337
    return dir;
194 terminx 338
}
339
 
1205 terminx 340
int32_t Bcorrectfilename(char *filename, int32_t removefn)
99 terminx 341
{
109 terminx 342
    char *fn;
795 terminx 343
    char *tokarr[64], *first, *next = NULL, *token;
1205 terminx 344
    int32_t i, ntok = 0, leadslash = 0, trailslash = 0;
109 terminx 345
 
1527 terminx 346
    fn = Bstrdup(filename);
109 terminx 347
    if (!fn) return -1;
348
 
584 terminx 349
    for (first=fn; *first; first++)
350
    {
99 terminx 351
#ifdef _WIN32
109 terminx 352
        if (*first == '\\') *first = '/';
99 terminx 353
#endif
109 terminx 354
    }
355
    leadslash = (*fn == '/');
356
    trailslash = (first>fn && first[-1] == '/');
99 terminx 357
 
109 terminx 358
    first = fn;
584 terminx 359
    do
360
    {
109 terminx 361
        token = Bstrtoken(first, "/", &next, 1);
362
        first = NULL;
363
        if (!token) break;
364
        else if (token[0] == 0) continue;
365
        else if (token[0] == '.' && token[1] == 0) continue;
366
        else if (token[0] == '.' && token[1] == '.' && token[2] == 0) ntok = max(0,ntok-1);
367
        else tokarr[ntok++] = token;
584 terminx 368
    }
369
    while (1);
109 terminx 370
 
584 terminx 371
    if (!trailslash && removefn) { ntok = max(0,ntok-1); trailslash = 1; }
109 terminx 372
    if (ntok == 0 && trailslash && leadslash) trailslash = 0;
373
 
374
    first = filename;
375
    if (leadslash) *(first++) = '/';
584 terminx 376
    for (i=0; i<ntok; i++)
377
    {
109 terminx 378
        if (i>0) *(first++) = '/';
379
        for (token=tokarr[i]; *token; token++)
380
            *(first++) = *token;
381
    }
382
    if (trailslash) *(first++) = '/';
383
    *(first++) = 0;
384
 
108 terminx 385
    Bfree(fn);
109 terminx 386
    return 0;
99 terminx 387
}
388
 
1205 terminx 389
int32_t Bcanonicalisefilename(char *filename, int32_t removefn)
99 terminx 390
{
4894 terminx 391
    char cwd[BMAX_PATH];
109 terminx 392
    char *fnp = filename;
4894 terminx 393
 
99 terminx 394
#ifdef _WIN32
4894 terminx 395
    int drv = 0;
109 terminx 396
 
4894 terminx 397
    if (filename[0] && filename[1] == ':')
109 terminx 398
    {
4894 terminx 399
        // filename is prefixed with a drive
400
        drv = toupper(filename[0]) - 'A' + 1;
401
        fnp += 2;
109 terminx 402
    }
4894 terminx 403
 
404
    if (!_getdcwd(drv, cwd, sizeof(cwd)))
405
        return -1;
406
 
407
    for (char *p = cwd; *p; p++)
408
        if (*p == '\\')
409
            *p = '/';
99 terminx 410
#else
4894 terminx 411
    if (!getcwd(cwd, sizeof(cwd)))
412
        return -1;
99 terminx 413
#endif
109 terminx 414
 
4894 terminx 415
    char *p = Bstrrchr(cwd, '/');
416
    if (!p || p[1])
417
        Bstrcat(cwd, "/");
418
 
419
    char fn[BMAX_PATH];
420
    Bstrcpy(fn, fnp);
421
 
99 terminx 422
#ifdef _WIN32
4894 terminx 423
    for (p = fn; *p; p++)
424
        if (*p == '\\')
425
            *p = '/';
99 terminx 426
#endif
109 terminx 427
 
584 terminx 428
    if (fn[0] != '/')
429
    {
109 terminx 430
        // we are dealing with a path relative to the current directory
4894 terminx 431
        Bstrcpy(filename, cwd);
432
        Bstrcat(filename, fn);
584 terminx 433
    }
434
    else
435
    {
99 terminx 436
#ifdef _WIN32
109 terminx 437
        filename[0] = cwd[0];
438
        filename[1] = ':';
439
        filename[2] = 0;
4894 terminx 440
        Bstrcat(filename, fn);
99 terminx 441
#else
4894 terminx 442
        Bstrcpy(filename, fn);
99 terminx 443
#endif
109 terminx 444
    }
445
    fnp = filename;
99 terminx 446
#ifdef _WIN32
4894 terminx 447
    fnp += 2;  // skip the drive
99 terminx 448
#endif
4894 terminx 449
    UNREFERENCED_PARAMETER(removefn);  // change the call below to use removefn instead of 1?
450
    return Bcorrectfilename(fnp, 1);
99 terminx 451
}
452
 
453
char *Bgetsystemdrives(void)
454
{
455
#ifdef _WIN32
109 terminx 456
    char *str, *p;
457
    DWORD drv, mask;
4894 terminx 458
    int32_t number = 0;
99 terminx 459
 
109 terminx 460
    drv = GetLogicalDrives();
4894 terminx 461
    if (drv == 0)
462
        return NULL;
99 terminx 463
 
4894 terminx 464
    for (mask = 1; mask < 0x8000000l; mask <<= 1)
584 terminx 465
    {
4894 terminx 466
        if ((drv & mask) == 0)
467
            continue;
109 terminx 468
        number++;
469
    }
99 terminx 470
 
4894 terminx 471
    str = p = (char *)Bmalloc(1 + (3 * number));
472
    if (!str)
473
        return NULL;
99 terminx 474
 
109 terminx 475
    number = 0;
4894 terminx 476
    for (mask = 1; mask < 0x8000000l; mask <<= 1, number++)
584 terminx 477
    {
4894 terminx 478
        if ((drv & mask) == 0)
479
            continue;
109 terminx 480
        *(p++) = 'A' + number;
481
        *(p++) = ':';
482
        *(p++) = 0;
483
    }
484
    *(p++) = 0;
485
 
486
    return str;
99 terminx 487
#else
109 terminx 488
    // Perhaps have Unix OS's put /, /home/user, and /mnt/* in the "drives" list?
489
    return NULL;
99 terminx 490
#endif
491
}
492
 
493
 
1205 terminx 494
int32_t Bfilelength(int32_t fd)
99 terminx 495
{
3168 helixhorne 496
    struct Bstat st;
4894 terminx 497
    return (Bfstat(fd, &st) < 0) ? -1 : (int32_t)(st.st_size);
99 terminx 498
}
499
 
500
 
584 terminx 501
typedef struct
502
{
99 terminx 503
#ifdef _MSC_VER
4325 terminx 504
    intptr_t dir;
109 terminx 505
    struct _finddata_t fid;
99 terminx 506
#else
109 terminx 507
    DIR *dir;
99 terminx 508
#endif
109 terminx 509
    struct Bdirent info;
1205 terminx 510
    int32_t status;
109 terminx 511
    char name[1];
99 terminx 512
} BDIR_real;
513
 
1762 terminx 514
BDIR *Bopendir(const char *name)
99 terminx 515
{
109 terminx 516
    BDIR_real *dirr;
99 terminx 517
#ifdef _MSC_VER
4894 terminx 518
    char *t, *tt;
519
    t = (char *)Bmalloc(Bstrlen(name) + 1 + 4);
520
    if (!t)
521
        return NULL;
99 terminx 522
#endif
523
 
4894 terminx 524
    dirr = (BDIR_real *)Bmalloc(sizeof(BDIR_real) + Bstrlen(name));
584 terminx 525
    if (!dirr)
526
    {
99 terminx 527
#ifdef _MSC_VER
1527 terminx 528
        Bfree(t);
99 terminx 529
#endif
109 terminx 530
        return NULL;
531
    }
99 terminx 532
 
533
#ifdef _MSC_VER
4894 terminx 534
    Bstrcpy(t, name);
535
    tt = t + Bstrlen(name) - 1;
536
    while (*tt == ' ' && tt > t) tt--;
537
    if (*tt != '/' && *tt != '\\')
538
        *(++tt) = '/';
109 terminx 539
    *(++tt) = '*';
540
    *(++tt) = '.';
541
    *(++tt) = '*';
542
    *(++tt) = 0;
543
 
4894 terminx 544
    dirr->dir = _findfirst(t, &dirr->fid);
1527 terminx 545
    Bfree(t);
584 terminx 546
    if (dirr->dir == -1)
547
    {
1527 terminx 548
        Bfree(dirr);
109 terminx 549
        return NULL;
550
    }
99 terminx 551
#else
109 terminx 552
    dirr->dir = opendir(name);
584 terminx 553
    if (dirr->dir == NULL)
554
    {
1527 terminx 555
        Bfree(dirr);
109 terminx 556
        return NULL;
557
    }
99 terminx 558
#endif
559
 
109 terminx 560
    dirr->status = 0;
4894 terminx 561
    Bstrcpy(dirr->name, name);
109 terminx 562
 
1762 terminx 563
    return (BDIR *)dirr;
99 terminx 564
}
565
 
4894 terminx 566
struct Bdirent *Breaddir(BDIR *dir)
99 terminx 567
{
1762 terminx 568
    BDIR_real *dirr = (BDIR_real *)dir;
99 terminx 569
 
570
#ifdef _MSC_VER
584 terminx 571
    if (dirr->status > 0)
572
    {
4894 terminx 573
        if (_findnext(dirr->dir, &dirr->fid) != 0)
584 terminx 574
        {
109 terminx 575
            dirr->status = -1;
576
            return NULL;
577
        }
578
    }
4894 terminx 579
    dirr->info.namlen = Bstrlen(dirr->fid.name);
109 terminx 580
    dirr->info.name = dirr->fid.name;
581
    dirr->status++;
99 terminx 582
#else
4894 terminx 583
    struct dirent *de = readdir(dirr->dir);
584 terminx 584
    if (de == NULL)
585
    {
109 terminx 586
        dirr->status = -1;
587
        return NULL;
584 terminx 588
    }
589
    else
590
    {
109 terminx 591
        dirr->status++;
592
    }
4894 terminx 593
    dirr->info.namlen = Bstrlen(de->d_name);
594
    dirr->info.name = de->d_name;
99 terminx 595
#endif
109 terminx 596
    dirr->info.mode = 0;
597
    dirr->info.size = 0;
598
    dirr->info.mtime = 0;
99 terminx 599
 
4894 terminx 600
    char *fn = (char *)Bmalloc(Bstrlen(dirr->name) + 1 + dirr->info.namlen + 1);
584 terminx 601
    if (fn)
602
    {
4894 terminx 603
        Bsprintf(fn, "%s/%s", dirr->name, dirr->info.name);
604
        struct Bstat st;
1652 terminx 605
        if (!Bstat(fn, &st))
584 terminx 606
        {
109 terminx 607
            dirr->info.mode = st.st_mode;
608
            dirr->info.size = st.st_size;
609
            dirr->info.mtime = st.st_mtime;
610
        }
1527 terminx 611
        Bfree(fn);
109 terminx 612
    }
99 terminx 613
 
109 terminx 614
    return &dirr->info;
99 terminx 615
}
616
 
1205 terminx 617
int32_t Bclosedir(BDIR *dir)
99 terminx 618
{
1762 terminx 619
    BDIR_real *dirr = (BDIR_real *)dir;
109 terminx 620
 
99 terminx 621
#ifdef _MSC_VER
109 terminx 622
    _findclose(dirr->dir);
99 terminx 623
#else
109 terminx 624
    closedir(dirr->dir);
99 terminx 625
#endif
1527 terminx 626
    Bfree(dirr);
99 terminx 627
 
109 terminx 628
    return 0;
99 terminx 629
}
630
 
631
 
4894 terminx 632
char *Bstrtoken(char *s, const char *delim, char **ptrptr, int chop)
99 terminx 633
{
4894 terminx 634
    if (!ptrptr)
635
        return NULL;
99 terminx 636
 
4894 terminx 637
    char *p = s ? s : *ptrptr;
99 terminx 638
 
4894 terminx 639
    if (!p)
640
        return NULL;
99 terminx 641
 
4894 terminx 642
    while (*p != 0 && Bstrchr(delim, *p)) p++;
99 terminx 643
 
584 terminx 644
    if (*p == 0)
645
    {
109 terminx 646
        *ptrptr = NULL;
647
        return NULL;
648
    }
4894 terminx 649
 
650
    char * const start = p;
651
 
652
    while (*p != 0 && !Bstrchr(delim, *p)) p++;
653
 
654
    if (*p == 0)
655
        *ptrptr = NULL;
584 terminx 656
    else
657
    {
4894 terminx 658
        if (chop)
659
            *(p++) = 0;
109 terminx 660
        *ptrptr = p;
661
    }
662
 
663
    return start;
99 terminx 664
}
665
 
2458 hendricks2 666
char *Bstrtolower(char *str)
667
{
4894 terminx 668
    if (!str)
669
        return NULL;
99 terminx 670
 
4894 terminx 671
    int len = Bstrlen(str);
2458 hendricks2 672
 
4894 terminx 673
    if (len <= 0)
674
        return str;
2458 hendricks2 675
 
4894 terminx 676
    int i = 0;
2458 hendricks2 677
 
4894 terminx 678
    do
679
    {
680
        *(str + i) = Btolower(*(str + i));
681
        i++;
682
    } while (--len);
683
 
2458 hendricks2 684
    return str;
685
}
686
 
687
 
109 terminx 688
//Brute-force case-insensitive, slash-insensitive, * and ? wildcard matcher
689
//Returns: 1:matches, 0:doesn't match
4658 terminx 690
#ifndef WITHKPLIB
691
extern char toupperlookup[256];
692
 
693
static int32_t wildmatch(const char *match, const char *wild)
99 terminx 694
{
109 terminx 695
    do
696
    {
4658 terminx 697
        if (*match && (toupperlookup[*wild] == toupperlookup[*match] || *wild == '?'))
109 terminx 698
        {
4658 terminx 699
            wild++, match++;
109 terminx 700
            continue;
701
        }
4658 terminx 702
        else if ((*match|*wild) == '\0')
703
            return 1;
704
        else if (*wild == '*')
705
        {
4922 terminx 706
            do { wild++; } while (*wild == '*');
707
            do
708
            {
709
                if (*wild == '\0')
710
                    return 1;
711
                while (*match && toupperlookup[*match] != toupperlookup[*wild]) match++;
712
                if (*match && *(match+1) && toupperlookup[*(match+1)] != toupperlookup[*(wild+1)])
713
                {
714
                    match++;
715
                    continue;
716
                }
717
                break;
718
            }
719
            while (1);
4658 terminx 720
            if (toupperlookup[*match] == toupperlookup[*wild])
721
                continue;
722
        }
723
        return 0;
4922 terminx 724
    }
725
    while (1);
4658 terminx 726
}
99 terminx 727
#endif
728
 
729
#if !defined(_WIN32)
730
char *Bstrlwr(char *s)
731
{
4894 terminx 732
    if (!s) return s;
109 terminx 733
    char *t = s;
584 terminx 734
    while (*t) { *t = Btolower(*t); t++; }
109 terminx 735
    return s;
99 terminx 736
}
737
 
738
char *Bstrupr(char *s)
739
{
4894 terminx 740
    if (!s) return s;
109 terminx 741
    char *t = s;
584 terminx 742
    while (*t) { *t = Btoupper(*t); t++; }
109 terminx 743
    return s;
99 terminx 744
}
745
#endif
746
 
747
 
748
//
1586 terminx 749
// Bgetsysmemsize() -- gets the amount of system memory in the machine
99 terminx 750
//
3116 hendricks2 751
#ifdef _WIN32
752
typedef BOOL (WINAPI *aGlobalMemoryStatusExType)(LPMEMORYSTATUSEX);
753
#endif
754
 
1762 terminx 755
uint32_t Bgetsysmemsize(void)
756
{
757
#ifdef _WIN32
2986 helixhorne 758
    uint32_t siz = UINT32_MAX;
1762 terminx 759
    HMODULE lib = LoadLibrary("KERNEL32.DLL");
99 terminx 760
 
1762 terminx 761
    if (lib)
762
    {
3116 hendricks2 763
        aGlobalMemoryStatusExType aGlobalMemoryStatusEx =
764
            (aGlobalMemoryStatusExType)GetProcAddress(lib, "GlobalMemoryStatusEx");
99 terminx 765
 
1762 terminx 766
        if (aGlobalMemoryStatusEx)
767
        {
768
            //WinNT
769
            MEMORYSTATUSEX memst;
770
            memst.dwLength = sizeof(MEMORYSTATUSEX);
771
            if (aGlobalMemoryStatusEx(&memst))
2986 helixhorne 772
                siz = (uint32_t)min(UINT32_MAX, memst.ullTotalPhys);
1762 terminx 773
        }
774
        else
775
        {
776
            // Yeah, there's enough Win9x hatred here that a perfectly good workaround
777
            // has been replaced by an error message.  Oh well, we don't support 9x anyway.
2458 hendricks2 778
            initprintf("Bgetsysmemsize(): error determining system memory size!\n");
1762 terminx 779
        }
99 terminx 780
 
1762 terminx 781
        FreeLibrary(lib);
782
    }
783
 
784
    return siz;
2628 helixhorne 785
#elif (defined(_SC_PAGE_SIZE) || defined(_SC_PAGESIZE)) && defined(_SC_PHYS_PAGES) && !defined(GEKKO)
2986 helixhorne 786
    uint32_t siz = UINT32_MAX;
1762 terminx 787
    int64_t scpagesiz, scphyspages;
788
 
789
#ifdef _SC_PAGE_SIZE
790
    scpagesiz = sysconf(_SC_PAGE_SIZE);
791
#else
792
    scpagesiz = sysconf(_SC_PAGESIZE);
793
#endif
794
    scphyspages = sysconf(_SC_PHYS_PAGES);
795
    if (scpagesiz >= 0 && scphyspages >= 0)
2986 helixhorne 796
        siz = (uint32_t)min(UINT32_MAX, (int64_t)scpagesiz * (int64_t)scphyspages);
1762 terminx 797
 
798
    //initprintf("Bgetsysmemsize(): %d pages of %d bytes, %d bytes of system memory\n",
799
    //          scphyspages, scpagesiz, siz);
800
 
801
    return siz;
802
#else
2986 helixhorne 803
    return UINT32_MAX;
1762 terminx 804
#endif
805
}
806
 
2628 helixhorne 807
#ifdef GEKKO
808
int access(const char *pathname, int mode)
809
{
810
    struct stat st;
811
    if (stat(pathname, &st)==-1)
812
        return -1;
1762 terminx 813
 
2628 helixhorne 814
    // TODO: Check mode against st_mode
3496 hendricks2 815
    UNREFERENCED_PARAMETER(mode);
1762 terminx 816
 
2628 helixhorne 817
    return 0;
818
}
819
#endif
820
 
4658 terminx 821
#define LIBDIVIDE_BODY
822
#include "libdivide.h"
823