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