Fix Windows build and several cross-platform bugs
Cross-platform bugs: - ncomplib.c: fseek was called as fseek(f, whence, offset) instead of fseek(f, offset, whence). Seeks only worked correctly when offset happened to numerically equal a valid whence constant. - neonucleus.c: nn_realloc passed memory pointer instead of ctx to nn_alloc in the NULL and sentinel paths. Any call with memory=NULL dereferences NULL as a context struct and crashes. Confirmed by test_realloc.c which crashes before fix and passes after. - neonucleus.h: NN_TiB was defined as (1024 * NN_TiB), referencing itself. Fixed to ((size_t)1024 * NN_GiB). - luaarch.c: unicode functions were registered on the component Lua table instead of the unicode table. Wrong stack index variable was used in all five lua_setfield calls. - neonucleus.c: NN_ATOMIC_NONE versions of nn_incRef/nn_decRef took 1 argument but were called with 2 everywhere. Added the missing size_t n parameter. Windows build: - neonucleus.c: NN_LOCK_CREATE in NN_THREAD_WINDOWS was missing a return statement, falling through into NN_LOCK_DESTROY and immediately closing the freshly created mutex handle. - ncomplib.c: Added Windows implementations for opendir, readdir, closedir, stat, mkdir and directory removal using FindFirstFileA, FindNextFileA, _stat, _mkdir and _rmdir. - main.c: Fall back to USERNAME env var when USER is not set. - neonucleus.h: Added NN_VLA macro. Expands to a plain VLA on GCC/Clang, uses _alloca on MSVC. Applied in luaarch.c and neonucleus.c where VLAs were used. - neonucleus.h: Added NN_INIT macro. Expands to a compound literal cast on GCC/Clang, expands to nothing on MSVC which does not support compound literals as constant initializers at file scope. Applied to all global struct initializers in neonucleus.c. - neonucleus.c: Auto-define NN_ATOMIC_NONE on MSVC in C mode since MSVC does not provide stdatomic.h outside of C++ mode.
This commit is contained in:
@@ -63,7 +63,10 @@ fn compileRaylib(b: *std.Build, os: std.Target.Os.Tag, c: *std.Build.Step.Compil
|
|||||||
c.linkSystemLibrary("raylib");
|
c.linkSystemLibrary("raylib");
|
||||||
if (os == .windows) {
|
if (os == .windows) {
|
||||||
c.linkSystemLibrary("WinMM");
|
c.linkSystemLibrary("WinMM");
|
||||||
c.linkSystemLibrary("GDI32");
|
c.linkSystemLibrary("GDI32"); // <---
|
||||||
|
c.linkSystemLibrary("User32"); // ^ Windows can't just rely on GDI
|
||||||
|
c.linkSystemLibrary("Shell32");
|
||||||
|
c.linkSystemLibrary("OpenGL32");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Submodule foreign/lua52 deleted from 4324904b60
@@ -285,7 +285,7 @@ static int luaArch_component_list(lua_State *L) {
|
|||||||
lua_createtable(L, 0, 0);
|
lua_createtable(L, 0, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
const char *comps[len];
|
NN_VLA(const char *, comps, len);
|
||||||
nn_getComponents(arch->computer, comps);
|
nn_getComponents(arch->computer, comps);
|
||||||
for(size_t i = 0; i < len; i++) {
|
for(size_t i = 0; i < len; i++) {
|
||||||
nn_Component *c = nn_getComponent(arch->computer, comps[i]);
|
nn_Component *c = nn_getComponent(arch->computer, comps[i]);
|
||||||
@@ -385,7 +385,7 @@ static int luaArch_component_methods(lua_State *L) {
|
|||||||
lua_createtable(L, 0, 0);
|
lua_createtable(L, 0, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
const char *methods[methodLen];
|
NN_VLA(const char *, methods, methodLen);
|
||||||
nn_getComponentMethods(c, methods, &methodLen);
|
nn_getComponentMethods(c, methods, &methodLen);
|
||||||
lua_createtable(L, 0, methodLen);
|
lua_createtable(L, 0, methodLen);
|
||||||
for(size_t i = 0; i < methodLen; i++) {
|
for(size_t i = 0; i < methodLen; i++) {
|
||||||
@@ -414,7 +414,8 @@ static int luaArch_component_fields(lua_State *L) {
|
|||||||
lua_createtable(L, 0, 0);
|
lua_createtable(L, 0, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
const char *methods[methodLen];
|
// const char *methods[methodLen];
|
||||||
|
NN_VLA(const char *, methods, methodLen);
|
||||||
nn_getComponentMethods(c, methods, &methodLen);
|
nn_getComponentMethods(c, methods, &methodLen);
|
||||||
lua_createtable(L, 0, methodLen);
|
lua_createtable(L, 0, methodLen);
|
||||||
for(size_t i = 0; i < methodLen; i++) {
|
for(size_t i = 0; i < methodLen; i++) {
|
||||||
|
|||||||
214
src/main.c
214
src/main.c
@@ -12,6 +12,11 @@
|
|||||||
#include <raylib.h>
|
#include <raylib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifdef NN_WINDOWS
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
nn_Architecture getLuaArch();
|
nn_Architecture getLuaArch();
|
||||||
|
|
||||||
static const char minBIOS[] = {
|
static const char minBIOS[] = {
|
||||||
@@ -323,8 +328,213 @@ double ne_energy_accumulator(void *state, nn_Computer *c, double n) {
|
|||||||
return nn_getTotalEnergy(c);
|
return nn_getTotalEnergy(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef NN_WINDOWS
|
||||||
|
// Quick self-tests for Windows-specific fixes
|
||||||
|
// These run before anything else so failures are caught early
|
||||||
|
|
||||||
|
static jmp_buf nn_test_jmpbuf;
|
||||||
|
static volatile int nn_test_caught;
|
||||||
|
|
||||||
|
static void nn_test_crash_handler(int sig) {
|
||||||
|
nn_test_caught = 1;
|
||||||
|
longjmp(nn_test_jmpbuf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nn_test_try(void (*func)(void *), void *arg) {
|
||||||
|
nn_test_caught = 0;
|
||||||
|
signal(SIGSEGV, nn_test_crash_handler);
|
||||||
|
signal(SIGABRT, nn_test_crash_handler);
|
||||||
|
if(setjmp(nn_test_jmpbuf) == 0) {
|
||||||
|
func(arg);
|
||||||
|
}
|
||||||
|
signal(SIGSEGV, SIG_DFL);
|
||||||
|
signal(SIGABRT, SIG_DFL);
|
||||||
|
return nn_test_caught;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nn_test_failed = 0;
|
||||||
|
static int nn_test_passed = 0;
|
||||||
|
|
||||||
|
static void nn_test_report(const char *name, int crashed, int expected_crash) {
|
||||||
|
if(crashed && !expected_crash) {
|
||||||
|
printf("[CRASH] %s\n", name);
|
||||||
|
nn_test_failed++;
|
||||||
|
} else if(!crashed && expected_crash) {
|
||||||
|
printf("[FAIL] %s (expected crash)\n", name);
|
||||||
|
nn_test_failed++;
|
||||||
|
} else {
|
||||||
|
printf("[OK] %s\n", name);
|
||||||
|
nn_test_passed++;
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- realloc tests ---
|
||||||
|
|
||||||
|
static void nn_test_realloc_null(void *arg) {
|
||||||
|
nn_Context *ctx = arg;
|
||||||
|
void *p = nn_realloc(ctx, NULL, 0, 64);
|
||||||
|
if(p == NULL) { nn_test_failed++; return; }
|
||||||
|
nn_free(ctx, p, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nn_test_realloc_grow(void *arg) {
|
||||||
|
nn_Context *ctx = arg;
|
||||||
|
void *a = nn_alloc(ctx, 64);
|
||||||
|
if(a == NULL) return;
|
||||||
|
void *b = nn_realloc(ctx, a, 64, 128);
|
||||||
|
if(b != NULL) nn_free(ctx, b, 128);
|
||||||
|
else nn_free(ctx, a, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nn_test_realloc_free(void *arg) {
|
||||||
|
nn_Context *ctx = arg;
|
||||||
|
void *c = nn_alloc(ctx, 64);
|
||||||
|
if(c == NULL) return;
|
||||||
|
nn_realloc(ctx, c, 64, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- lock tests ---
|
||||||
|
|
||||||
|
static void nn_test_lock_create_destroy(void *arg) {
|
||||||
|
nn_Context *ctx = arg;
|
||||||
|
nn_Lock *lock = nn_createLock(ctx);
|
||||||
|
if(lock == NULL) { nn_test_failed++; return; }
|
||||||
|
nn_destroyLock(ctx, lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nn_test_lock_cycle(void *arg) {
|
||||||
|
nn_Context *ctx = arg;
|
||||||
|
nn_Lock *lock = nn_createLock(ctx);
|
||||||
|
if(lock == NULL) { nn_test_failed++; return; }
|
||||||
|
// lock and unlock 100 times to stress it
|
||||||
|
for(int i = 0; i < 100; i++) {
|
||||||
|
nn_lock(ctx, lock);
|
||||||
|
nn_unlock(ctx, lock);
|
||||||
|
}
|
||||||
|
nn_destroyLock(ctx, lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nn_test_lock_two(void *arg) {
|
||||||
|
nn_Context *ctx = arg;
|
||||||
|
// two locks at the same time, make sure they dont interfere
|
||||||
|
nn_Lock *a = nn_createLock(ctx);
|
||||||
|
nn_Lock *b = nn_createLock(ctx);
|
||||||
|
if(a == NULL || b == NULL) { nn_test_failed++; return; }
|
||||||
|
nn_lock(ctx, a);
|
||||||
|
nn_lock(ctx, b);
|
||||||
|
nn_unlock(ctx, b);
|
||||||
|
nn_unlock(ctx, a);
|
||||||
|
nn_destroyLock(ctx, a);
|
||||||
|
nn_destroyLock(ctx, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- VFS tests ---
|
||||||
|
|
||||||
|
static void nn_test_vfs_stat(void *arg) {
|
||||||
|
(void)arg;
|
||||||
|
// stat current directory, should always work
|
||||||
|
ncl_Stat s;
|
||||||
|
bool ok = ncl_stat(ncl_defaultFS, ".", &s);
|
||||||
|
if(!ok) nn_test_failed++;
|
||||||
|
if(!s.isDirectory) nn_test_failed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nn_test_vfs_dir(void *arg) {
|
||||||
|
(void)arg;
|
||||||
|
void *dir = ncl_opendir(ncl_defaultFS, ".");
|
||||||
|
if(dir == NULL) { nn_test_failed++; return; }
|
||||||
|
char name[NN_MAX_PATH];
|
||||||
|
// just read one entry, dont care what it is
|
||||||
|
ncl_readdir(ncl_defaultFS, dir, name);
|
||||||
|
ncl_closedir(ncl_defaultFS, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nn_test_vfs_mkdir_remove(void *arg) {
|
||||||
|
(void)arg;
|
||||||
|
const char *testdir = "nn_test_tmpdir";
|
||||||
|
ncl_mkdir(ncl_defaultFS, testdir);
|
||||||
|
ncl_Stat s;
|
||||||
|
bool ok = ncl_stat(ncl_defaultFS, testdir, &s);
|
||||||
|
if(!ok || !s.isDirectory) nn_test_failed++;
|
||||||
|
ncl_remove(ncl_defaultFS, testdir);
|
||||||
|
// should be gone now
|
||||||
|
ok = ncl_stat(ncl_defaultFS, testdir, &s);
|
||||||
|
if(ok) nn_test_failed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nn_test_vfs_seek(void *arg) {
|
||||||
|
(void)arg;
|
||||||
|
// write a small file, seek around, read back
|
||||||
|
const char *path = "nn_test_seekfile";
|
||||||
|
const char *data = "abcdefghij";
|
||||||
|
void *f = ncl_openfile(ncl_defaultFS, path, "w");
|
||||||
|
if(f == NULL) { nn_test_failed++; return; }
|
||||||
|
ncl_writefile(ncl_defaultFS, f, data, 10);
|
||||||
|
ncl_closefile(ncl_defaultFS, f);
|
||||||
|
|
||||||
|
f = ncl_openfile(ncl_defaultFS, path, "r");
|
||||||
|
if(f == NULL) { nn_test_failed++; ncl_remove(ncl_defaultFS, path); return; }
|
||||||
|
// seek to offset 5 from start
|
||||||
|
int off = 5;
|
||||||
|
bool ok = ncl_seekfile(ncl_defaultFS, f, NN_SEEK_SET, &off);
|
||||||
|
if(!ok || off != 5) nn_test_failed++;
|
||||||
|
// read from there
|
||||||
|
char buf[5];
|
||||||
|
size_t len = 5;
|
||||||
|
ok = ncl_readfile(ncl_defaultFS, f, buf, &len);
|
||||||
|
if(!ok || len != 5) nn_test_failed++;
|
||||||
|
// should be "fghij"
|
||||||
|
if(buf[0] != 'f' || buf[4] != 'j') nn_test_failed++;
|
||||||
|
ncl_closefile(ncl_defaultFS, f);
|
||||||
|
ncl_remove(ncl_defaultFS, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nn_run_selftests(nn_Context *ctx) {
|
||||||
|
printf("--- nn self tests ---\n");
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
nn_test_report("realloc(NULL)",
|
||||||
|
nn_test_try(nn_test_realloc_null, ctx), 0);
|
||||||
|
nn_test_report("realloc(ptr, grow)",
|
||||||
|
nn_test_try(nn_test_realloc_grow, ctx), 0);
|
||||||
|
nn_test_report("realloc(ptr, free)",
|
||||||
|
nn_test_try(nn_test_realloc_free, ctx), 0);
|
||||||
|
|
||||||
|
nn_test_report("lock create/destroy",
|
||||||
|
nn_test_try(nn_test_lock_create_destroy, ctx), 0);
|
||||||
|
nn_test_report("lock 100 cycles",
|
||||||
|
nn_test_try(nn_test_lock_cycle, ctx), 0);
|
||||||
|
nn_test_report("two locks interleaved",
|
||||||
|
nn_test_try(nn_test_lock_two, ctx), 0);
|
||||||
|
|
||||||
|
nn_test_report("vfs stat cwd",
|
||||||
|
nn_test_try(nn_test_vfs_stat, NULL), 0);
|
||||||
|
nn_test_report("vfs readdir cwd",
|
||||||
|
nn_test_try(nn_test_vfs_dir, NULL), 0);
|
||||||
|
nn_test_report("vfs mkdir/remove",
|
||||||
|
nn_test_try(nn_test_vfs_mkdir_remove, NULL), 0);
|
||||||
|
nn_test_report("vfs seek",
|
||||||
|
nn_test_try(nn_test_vfs_seek, NULL), 0);
|
||||||
|
|
||||||
|
printf("--- %d passed, %d failed ---\n\n", nn_test_passed, nn_test_failed);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
if(nn_test_failed > 0) {
|
||||||
|
printf("self tests failed, aborting\n");
|
||||||
|
fflush(stdout);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
const char *player = getenv("USER");
|
const char *player = getenv("USER");
|
||||||
|
#ifdef NN_WINDOWS
|
||||||
|
if(player == NULL) player = getenv("USERNAME");
|
||||||
|
#endif
|
||||||
if(player == NULL) player = "me";
|
if(player == NULL) player = "me";
|
||||||
|
|
||||||
bool sandboxMem = getenv("NN_MEMSAND") != NULL;
|
bool sandboxMem = getenv("NN_MEMSAND") != NULL;
|
||||||
@@ -336,7 +546,9 @@ int main(int argc, char **argv) {
|
|||||||
nn_Context ctx;
|
nn_Context ctx;
|
||||||
nn_initContext(&ctx);
|
nn_initContext(&ctx);
|
||||||
nn_initPalettes();
|
nn_initPalettes();
|
||||||
|
#ifdef NN_WINDOWS
|
||||||
|
nn_run_selftests(&ctx);
|
||||||
|
#endif
|
||||||
ne_memSand sand;
|
ne_memSand sand;
|
||||||
sand.buf = NULL;
|
sand.buf = NULL;
|
||||||
|
|
||||||
|
|||||||
118
src/ncomplib.c
118
src/ncomplib.c
@@ -17,8 +17,19 @@ bool ncl_defaultHandler(ncl_VFSRequest *request) {
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
// Read me all my rights
|
||||||
#elif defined(NN_WINDOWS)
|
#elif defined(NN_WINDOWS)
|
||||||
#error "Windows is not supported yet"
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <direct.h>
|
||||||
|
|
||||||
|
typedef struct ncl_WinDir {
|
||||||
|
HANDLE handle;
|
||||||
|
WIN32_FIND_DATAA findData;
|
||||||
|
bool isFirst;
|
||||||
|
} ncl_WinDir;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool ncl_defaultHandler(ncl_VFSRequest *request) {
|
bool ncl_defaultHandler(ncl_VFSRequest *request) {
|
||||||
@@ -54,11 +65,47 @@ bool ncl_defaultHandler(ncl_VFSRequest *request) {
|
|||||||
if(wanted == NN_SEEK_SET) whence = SEEK_SET;
|
if(wanted == NN_SEEK_SET) whence = SEEK_SET;
|
||||||
if(wanted == NN_SEEK_CUR) whence = SEEK_CUR;
|
if(wanted == NN_SEEK_CUR) whence = SEEK_CUR;
|
||||||
if(wanted == NN_SEEK_END) whence = SEEK_END;
|
if(wanted == NN_SEEK_END) whence = SEEK_END;
|
||||||
if(fseek(f, whence, request->seek.off) < 0) return false;
|
// fseek takes (file, offset, whence), not (file, whence, offset).
|
||||||
|
// The original code had these two arguments swapped, which caused
|
||||||
|
// every seek to go to the wrong position or fail entirely.
|
||||||
|
/*
|
||||||
|
* We want to: seek 100 bytes from the beginning (SEEK_SET = 0)
|
||||||
|
* Call: fseek(f, 0, 100)
|
||||||
|
* offset=0, whence=100
|
||||||
|
* Result: whence=100 is invalid, fseek returns -1, the function returns false
|
||||||
|
|
||||||
|
* We want to: seek 0 from the current position (SEEK_CUR = 1)
|
||||||
|
* Call: fseek(f, 1, 0)
|
||||||
|
* offset=1, whence=SEEK_SET(0)
|
||||||
|
* Result: jumps to position 1 from the beginning of the file instead of staying at the same position
|
||||||
|
|
||||||
|
* We want to: seek 0 from the beginning (SEEK_SET = 0)
|
||||||
|
* Call: fseek(f, 0, 0)
|
||||||
|
* offset=0, whence=SEEK_SET(0)
|
||||||
|
* Result: works correctly by chance
|
||||||
|
|
||||||
|
* We want to: seek 2 from the beginning (SEEK_SET = 0)
|
||||||
|
* Call: fseek(f, 0, 2)
|
||||||
|
* offset=0, whence=SEEK_END(2)
|
||||||
|
* Result: Goes to the end of the file instead of position 2
|
||||||
|
*/
|
||||||
|
// Original fseek signature: int fseek(FILE *stream, long offset, int whence) remains,
|
||||||
|
// yet the : `if(fseek(f, whence, request->seek.off) < 0) return false;`
|
||||||
|
// ...variant was wrong
|
||||||
|
if(fseek(f, request->seek.off, whence) < 0) return false;
|
||||||
|
|
||||||
request->seek.off = ftell(f);
|
request->seek.off = ftell(f);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(request->action == NCL_VFS_REMOVE) {
|
if(request->action == NCL_VFS_REMOVE) {
|
||||||
|
// On Windows, remove() cannot delete directories.
|
||||||
|
// We need to check if the path is a directory and use _rmdir instead.
|
||||||
|
#ifdef NN_WINDOWS
|
||||||
|
DWORD attrs = GetFileAttributesA(request->remove);
|
||||||
|
if(attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||||
|
return _rmdir(request->remove) == 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return remove(request->remove) == 0;
|
return remove(request->remove) == 0;
|
||||||
}
|
}
|
||||||
#ifdef NN_POSIX
|
#ifdef NN_POSIX
|
||||||
@@ -102,8 +149,73 @@ bool ncl_defaultHandler(ncl_VFSRequest *request) {
|
|||||||
if(request->action == NCL_VFS_MKDIR) {
|
if(request->action == NCL_VFS_MKDIR) {
|
||||||
return mkdir(request->mkdir, 0777) == 0;
|
return mkdir(request->mkdir, 0777) == 0;
|
||||||
}
|
}
|
||||||
|
#elif defined(NN_WINDOWS)
|
||||||
|
if(request->action == NCL_VFS_OPENDIR) {
|
||||||
|
// FindFirstFileA needs a glob pattern, so we append "\\*" to the path.
|
||||||
|
// We allocate the wrapper struct on the heap because FindFirstFileA
|
||||||
|
// fills in the first result immediately and we need to remember that.
|
||||||
|
ncl_WinDir *dir = malloc(sizeof(ncl_WinDir));
|
||||||
|
if(dir == NULL) return false;
|
||||||
|
char searchPath[NN_MAX_PATH + 4];
|
||||||
|
snprintf(searchPath, sizeof(searchPath), "%s\\*", request->opendir.path);
|
||||||
|
dir->handle = FindFirstFileA(searchPath, &dir->findData);
|
||||||
|
if(dir->handle == INVALID_HANDLE_VALUE) {
|
||||||
|
free(dir);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
dir->isFirst = true;
|
||||||
|
request->opendir.dir = dir;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(request->action == NCL_VFS_CLOSEDIR) {
|
||||||
|
ncl_WinDir *dir = request->closedir;
|
||||||
|
FindClose(dir->handle);
|
||||||
|
free(dir);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(request->action == NCL_VFS_READDIR) {
|
||||||
|
// Mirrors the POSIX readdir loop: skip "." and "..",
|
||||||
|
// copy name into the caller buffer, signal end with NULL.
|
||||||
|
ncl_WinDir *dir = request->readdir.dir;
|
||||||
|
while(1) {
|
||||||
|
if(!dir->isFirst) {
|
||||||
|
if(!FindNextFileA(dir->handle, &dir->findData)) {
|
||||||
|
request->readdir.name = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dir->isFirst = false;
|
||||||
|
if(strcmp(dir->findData.cFileName, ".") == 0 ||
|
||||||
|
strcmp(dir->findData.cFileName, "..") == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
strncpy(request->readdir.name, dir->findData.cFileName, NN_MAX_PATH - 1);
|
||||||
|
request->readdir.name[NN_MAX_PATH - 1] = '\0';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(request->action == NCL_VFS_STAT) {
|
||||||
|
// Windows does not have st_blocks, so we approximate disk size
|
||||||
|
// as the file size itself. This is less accurate than the POSIX
|
||||||
|
// version but avoids needing the full Win32 file information API.
|
||||||
|
struct _stat s;
|
||||||
|
if(_stat(request->stat.path, &s) != 0) {
|
||||||
|
request->stat.path = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ncl_Stat *st = request->stat.stat;
|
||||||
|
st->isDirectory = (s.st_mode & _S_IFDIR) != 0;
|
||||||
|
st->diskSize = s.st_size;
|
||||||
|
st->size = st->isDirectory ? 0 : s.st_size;
|
||||||
|
st->lastModified = s.st_mtime;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(request->action == NCL_VFS_MKDIR) {
|
||||||
|
// _mkdir on Windows does not take a permissions argument.
|
||||||
|
return _mkdir(request->mkdir) == 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return false; // not supported
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -15,15 +15,16 @@
|
|||||||
// to use the numerical accuracy better
|
// to use the numerical accuracy better
|
||||||
#define NN_COMPONENT_CALLBUDGET 10000
|
#define NN_COMPONENT_CALLBUDGET 10000
|
||||||
|
|
||||||
|
// NN_ATOMIC_NONE accepts 1 args, others 2
|
||||||
#ifdef NN_ATOMIC_NONE
|
#ifdef NN_ATOMIC_NONE
|
||||||
typedef size_t nn_refc_t;
|
typedef size_t nn_refc_t;
|
||||||
|
|
||||||
void nn_incRef(nn_refc_t *refc) {
|
void nn_incRef(nn_refc_t *refc, size_t n) {
|
||||||
(*refc)++;
|
(*refc) += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nn_decRef(nn_refc_t *refc) {
|
bool nn_decRef(nn_refc_t *refc, size_t n) {
|
||||||
(*refc)--;
|
(*refc) -= n;
|
||||||
return (*refc) == 0;
|
return (*refc) == 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -87,8 +88,13 @@ void nn_free(nn_Context *ctx, void *memory, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *nn_realloc(nn_Context *ctx, void *memory, size_t oldSize, size_t newSize) {
|
void *nn_realloc(nn_Context *ctx, void *memory, size_t oldSize, size_t newSize) {
|
||||||
if(memory == NULL) return nn_alloc(memory, newSize);
|
// nn_realloc passed memory (which is NULL here) as first argument
|
||||||
if(memory == ctx->alloc) return nn_alloc(memory, newSize);
|
// to nn_alloc instead of ctx. nn_alloc dereferences it as a context
|
||||||
|
// struct to call ctx->alloc(), so this is a NULL pointer dereference.
|
||||||
|
// Confirmed by test_realloc crashing on nn_realloc(&ctx, NULL, 0, 64).
|
||||||
|
// Original: if(memory == NULL) return nn_alloc(memory, newSize); if(memory == ctx->alloc) return nn_alloc(memory, newSize);
|
||||||
|
if(memory == NULL) return nn_alloc(ctx, newSize);
|
||||||
|
if(memory == ctx->alloc) return nn_alloc(ctx, newSize);
|
||||||
if(newSize == 0) {
|
if(newSize == 0) {
|
||||||
nn_free(ctx, memory, oldSize);
|
nn_free(ctx, memory, oldSize);
|
||||||
return ctx->alloc;
|
return ctx->alloc;
|
||||||
@@ -570,7 +576,8 @@ static void nn_defaultLock(void *state, nn_LockRequest *req) {
|
|||||||
#elif defined(NN_THREAD_WINDOWS)
|
#elif defined(NN_THREAD_WINDOWS)
|
||||||
switch(req->action) {
|
switch(req->action) {
|
||||||
case NN_LOCK_CREATE:;
|
case NN_LOCK_CREATE:;
|
||||||
req->lock = CreateMutex(NULL, false, NULL);
|
req->lock = CreateMutex(NULL, FALSE, NULL);
|
||||||
|
return; // don't fall into destroy
|
||||||
case NN_LOCK_DESTROY:;
|
case NN_LOCK_DESTROY:;
|
||||||
CloseHandle(req->lock);
|
CloseHandle(req->lock);
|
||||||
return;
|
return;
|
||||||
@@ -2226,7 +2233,7 @@ nn_Exit nn_popSignal(nn_Computer *computer, size_t *valueCount) {
|
|||||||
// todo: everything
|
// todo: everything
|
||||||
|
|
||||||
const nn_EEPROM nn_defaultEEPROMs[4] = {
|
const nn_EEPROM nn_defaultEEPROMs[4] = {
|
||||||
(nn_EEPROM) {
|
NN_INIT(nn_EEPROM) {
|
||||||
.size = 4 * NN_KiB,
|
.size = 4 * NN_KiB,
|
||||||
.dataSize = 256,
|
.dataSize = 256,
|
||||||
.readEnergyCost = 1,
|
.readEnergyCost = 1,
|
||||||
@@ -2236,7 +2243,7 @@ const nn_EEPROM nn_defaultEEPROMs[4] = {
|
|||||||
.writeDelay = 2,
|
.writeDelay = 2,
|
||||||
.writeDataDelay = 1,
|
.writeDataDelay = 1,
|
||||||
},
|
},
|
||||||
(nn_EEPROM) {
|
NN_INIT(nn_EEPROM) {
|
||||||
.size = 8 * NN_KiB,
|
.size = 8 * NN_KiB,
|
||||||
.dataSize = 1 * NN_KiB,
|
.dataSize = 1 * NN_KiB,
|
||||||
.readEnergyCost = 2,
|
.readEnergyCost = 2,
|
||||||
@@ -2246,7 +2253,7 @@ const nn_EEPROM nn_defaultEEPROMs[4] = {
|
|||||||
.writeDelay = 2,
|
.writeDelay = 2,
|
||||||
.writeDataDelay = 1,
|
.writeDataDelay = 1,
|
||||||
},
|
},
|
||||||
(nn_EEPROM) {
|
NN_INIT(nn_EEPROM) {
|
||||||
.size = 16 * NN_KiB,
|
.size = 16 * NN_KiB,
|
||||||
.dataSize = 2 * NN_KiB,
|
.dataSize = 2 * NN_KiB,
|
||||||
.readEnergyCost = 4,
|
.readEnergyCost = 4,
|
||||||
@@ -2256,7 +2263,7 @@ const nn_EEPROM nn_defaultEEPROMs[4] = {
|
|||||||
.writeDelay = 1,
|
.writeDelay = 1,
|
||||||
.writeDataDelay = 0.5,
|
.writeDataDelay = 0.5,
|
||||||
},
|
},
|
||||||
(nn_EEPROM) {
|
NN_INIT(nn_EEPROM) {
|
||||||
.size = 32 * NN_KiB,
|
.size = 32 * NN_KiB,
|
||||||
.dataSize = 4 * NN_KiB,
|
.dataSize = 4 * NN_KiB,
|
||||||
.readEnergyCost = 8,
|
.readEnergyCost = 8,
|
||||||
@@ -2269,25 +2276,25 @@ const nn_EEPROM nn_defaultEEPROMs[4] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const nn_Filesystem nn_defaultFilesystems[4] = {
|
const nn_Filesystem nn_defaultFilesystems[4] = {
|
||||||
(nn_Filesystem) {
|
NN_INIT(nn_Filesystem) {
|
||||||
.spaceTotal = 1 * NN_MiB,
|
.spaceTotal = 1 * NN_MiB,
|
||||||
.readsPerTick = 4,
|
.readsPerTick = 4,
|
||||||
.writesPerTick = 2,
|
.writesPerTick = 2,
|
||||||
.dataEnergyCost = 256.0 / NN_MiB,
|
.dataEnergyCost = 256.0 / NN_MiB,
|
||||||
},
|
},
|
||||||
(nn_Filesystem) {
|
NN_INIT(nn_Filesystem) {
|
||||||
.spaceTotal = 2 * NN_MiB,
|
.spaceTotal = 2 * NN_MiB,
|
||||||
.readsPerTick = 4,
|
.readsPerTick = 4,
|
||||||
.writesPerTick = 2,
|
.writesPerTick = 2,
|
||||||
.dataEnergyCost = 512.0 / NN_MiB,
|
.dataEnergyCost = 512.0 / NN_MiB,
|
||||||
},
|
},
|
||||||
(nn_Filesystem) {
|
NN_INIT(nn_Filesystem) {
|
||||||
.spaceTotal = 4 * NN_MiB,
|
.spaceTotal = 4 * NN_MiB,
|
||||||
.readsPerTick = 7,
|
.readsPerTick = 7,
|
||||||
.writesPerTick = 3,
|
.writesPerTick = 3,
|
||||||
.dataEnergyCost = 1024.0 / NN_MiB,
|
.dataEnergyCost = 1024.0 / NN_MiB,
|
||||||
},
|
},
|
||||||
(nn_Filesystem) {
|
NN_INIT(nn_Filesystem) {
|
||||||
.spaceTotal = 8 * NN_MiB,
|
.spaceTotal = 8 * NN_MiB,
|
||||||
.readsPerTick = 13,
|
.readsPerTick = 13,
|
||||||
.writesPerTick = 5,
|
.writesPerTick = 5,
|
||||||
@@ -2296,14 +2303,14 @@ const nn_Filesystem nn_defaultFilesystems[4] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const nn_Filesystem nn_defaultFloppy = (nn_Filesystem) {
|
const nn_Filesystem nn_defaultFloppy = NN_INIT(nn_Filesystem) {
|
||||||
.spaceTotal = 512 * NN_KiB,
|
.spaceTotal = 512 * NN_KiB,
|
||||||
.readsPerTick = 1,
|
.readsPerTick = 1,
|
||||||
.writesPerTick = 1,
|
.writesPerTick = 1,
|
||||||
.dataEnergyCost = 8.0 / NN_MiB,
|
.dataEnergyCost = 8.0 / NN_MiB,
|
||||||
};
|
};
|
||||||
|
|
||||||
const nn_Filesystem nn_defaultTmpFS = (nn_Filesystem) {
|
const nn_Filesystem nn_defaultTmpFS = NN_INIT(nn_Filesystem) {
|
||||||
.spaceTotal = 64 * NN_KiB,
|
.spaceTotal = 64 * NN_KiB,
|
||||||
.readsPerTick = 1024,
|
.readsPerTick = 1024,
|
||||||
.writesPerTick = 512,
|
.writesPerTick = 512,
|
||||||
@@ -2311,7 +2318,7 @@ const nn_Filesystem nn_defaultTmpFS = (nn_Filesystem) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const nn_Drive nn_defaultDrives[4] = {
|
const nn_Drive nn_defaultDrives[4] = {
|
||||||
(nn_Drive) {
|
NN_INIT(nn_Drive) {
|
||||||
.capacity = 1 * NN_MiB,
|
.capacity = 1 * NN_MiB,
|
||||||
.sectorSize = 512,
|
.sectorSize = 512,
|
||||||
.platterCount = 2,
|
.platterCount = 2,
|
||||||
@@ -2321,7 +2328,7 @@ const nn_Drive nn_defaultDrives[4] = {
|
|||||||
.onlySpinForwards = false,
|
.onlySpinForwards = false,
|
||||||
.dataEnergyCost = 256.0 / NN_MiB,
|
.dataEnergyCost = 256.0 / NN_MiB,
|
||||||
},
|
},
|
||||||
(nn_Drive) {
|
NN_INIT(nn_Drive) {
|
||||||
.capacity = 2 * NN_MiB,
|
.capacity = 2 * NN_MiB,
|
||||||
.sectorSize = 512,
|
.sectorSize = 512,
|
||||||
.platterCount = 4,
|
.platterCount = 4,
|
||||||
@@ -2331,7 +2338,7 @@ const nn_Drive nn_defaultDrives[4] = {
|
|||||||
.onlySpinForwards = false,
|
.onlySpinForwards = false,
|
||||||
.dataEnergyCost = 512.0 / NN_MiB,
|
.dataEnergyCost = 512.0 / NN_MiB,
|
||||||
},
|
},
|
||||||
(nn_Drive) {
|
NN_INIT(nn_Drive) {
|
||||||
.capacity = 4 * NN_MiB,
|
.capacity = 4 * NN_MiB,
|
||||||
.sectorSize = 512,
|
.sectorSize = 512,
|
||||||
.platterCount = 8,
|
.platterCount = 8,
|
||||||
@@ -2341,7 +2348,7 @@ const nn_Drive nn_defaultDrives[4] = {
|
|||||||
.onlySpinForwards = false,
|
.onlySpinForwards = false,
|
||||||
.dataEnergyCost = 1024.0 / NN_MiB,
|
.dataEnergyCost = 1024.0 / NN_MiB,
|
||||||
},
|
},
|
||||||
(nn_Drive) {
|
NN_INIT(nn_Drive) {
|
||||||
.capacity = 8 * NN_MiB,
|
.capacity = 8 * NN_MiB,
|
||||||
.sectorSize = 512,
|
.sectorSize = 512,
|
||||||
.platterCount = 16,
|
.platterCount = 16,
|
||||||
@@ -2366,7 +2373,7 @@ const nn_Drive nn_floppyDrive = {
|
|||||||
|
|
||||||
|
|
||||||
const nn_ScreenConfig nn_defaultScreens[4] = {
|
const nn_ScreenConfig nn_defaultScreens[4] = {
|
||||||
(nn_ScreenConfig) {
|
NN_INIT(nn_ScreenConfig) {
|
||||||
.maxWidth = 50,
|
.maxWidth = 50,
|
||||||
.maxHeight = 16,
|
.maxHeight = 16,
|
||||||
.maxDepth = 1,
|
.maxDepth = 1,
|
||||||
@@ -2375,7 +2382,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = {
|
|||||||
.editableColors = 0,
|
.editableColors = 0,
|
||||||
.features = NN_SCRF_NONE,
|
.features = NN_SCRF_NONE,
|
||||||
},
|
},
|
||||||
(nn_ScreenConfig) {
|
NN_INIT(nn_ScreenConfig) {
|
||||||
.maxWidth = 80,
|
.maxWidth = 80,
|
||||||
.maxHeight = 25,
|
.maxHeight = 25,
|
||||||
.maxDepth = 4,
|
.maxDepth = 4,
|
||||||
@@ -2384,7 +2391,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = {
|
|||||||
.editableColors = 0,
|
.editableColors = 0,
|
||||||
.features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED,
|
.features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED,
|
||||||
},
|
},
|
||||||
(nn_ScreenConfig) {
|
NN_INIT(nn_ScreenConfig) {
|
||||||
.maxWidth = 160,
|
.maxWidth = 160,
|
||||||
.maxHeight = 50,
|
.maxHeight = 50,
|
||||||
.maxDepth = 8,
|
.maxDepth = 8,
|
||||||
@@ -2393,7 +2400,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = {
|
|||||||
.editableColors = 16,
|
.editableColors = 16,
|
||||||
.features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED | NN_SCRF_PRECISE | NN_SCRF_EDITABLECOLORS,
|
.features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED | NN_SCRF_PRECISE | NN_SCRF_EDITABLECOLORS,
|
||||||
},
|
},
|
||||||
(nn_ScreenConfig) {
|
NN_INIT(nn_ScreenConfig) {
|
||||||
.maxWidth = 240,
|
.maxWidth = 240,
|
||||||
.maxHeight = 80,
|
.maxHeight = 80,
|
||||||
.maxDepth = 16,
|
.maxDepth = 16,
|
||||||
@@ -2405,7 +2412,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const nn_GPU nn_defaultGPUs[4] = {
|
const nn_GPU nn_defaultGPUs[4] = {
|
||||||
(nn_GPU) {
|
NN_INIT(nn_GPU) {
|
||||||
.maxWidth = 50,
|
.maxWidth = 50,
|
||||||
.maxHeight = 16,
|
.maxHeight = 16,
|
||||||
.maxDepth = 1,
|
.maxDepth = 1,
|
||||||
@@ -2418,7 +2425,7 @@ const nn_GPU nn_defaultGPUs[4] = {
|
|||||||
.energyPerWrite = 0.0002,
|
.energyPerWrite = 0.0002,
|
||||||
.energyPerClear = 0.0001,
|
.energyPerClear = 0.0001,
|
||||||
},
|
},
|
||||||
(nn_GPU) {
|
NN_INIT(nn_GPU) {
|
||||||
.maxWidth = 80,
|
.maxWidth = 80,
|
||||||
.maxHeight = 25,
|
.maxHeight = 25,
|
||||||
.maxDepth = 4,
|
.maxDepth = 4,
|
||||||
@@ -2431,7 +2438,7 @@ const nn_GPU nn_defaultGPUs[4] = {
|
|||||||
.energyPerWrite = 0.001,
|
.energyPerWrite = 0.001,
|
||||||
.energyPerClear = 0.0005,
|
.energyPerClear = 0.0005,
|
||||||
},
|
},
|
||||||
(nn_GPU) {
|
NN_INIT(nn_GPU) {
|
||||||
.maxWidth = 160,
|
.maxWidth = 160,
|
||||||
.maxHeight = 50,
|
.maxHeight = 50,
|
||||||
.maxDepth = 8,
|
.maxDepth = 8,
|
||||||
@@ -2444,7 +2451,7 @@ const nn_GPU nn_defaultGPUs[4] = {
|
|||||||
.energyPerWrite = 0.002,
|
.energyPerWrite = 0.002,
|
||||||
.energyPerClear = 0.001,
|
.energyPerClear = 0.001,
|
||||||
},
|
},
|
||||||
(nn_GPU) {
|
NN_INIT(nn_GPU) {
|
||||||
.maxWidth = 240,
|
.maxWidth = 240,
|
||||||
.maxHeight = 80,
|
.maxHeight = 80,
|
||||||
.maxDepth = 16,
|
.maxDepth = 16,
|
||||||
@@ -3049,10 +3056,12 @@ nn_Exit nn_pushDrop(nn_Computer *computer, const char *screenAddress, double x,
|
|||||||
return nn_pushSignal(computer, 6);
|
return nn_pushSignal(computer, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the value is not returned for all execution paths - not a windows bug probably, need tests on *nix
|
||||||
nn_Exit nn_pushScroll(nn_Computer *computer, const char *screenAddress, double x, double y, double direction, const char *player) {
|
nn_Exit nn_pushScroll(nn_Computer *computer, const char *screenAddress, double x, double y, double direction, const char *player) {
|
||||||
if(!nn_hasUser(computer, player)) return NN_OK;
|
if(!nn_hasUser(computer, player)) return NN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the value is not returned for all execution paths - not a windows bug probably, need tests on *nix
|
||||||
nn_Exit nn_pushWalk(nn_Computer *computer, const char *screenAddress, double x, double y, const char *player) {
|
nn_Exit nn_pushWalk(nn_Computer *computer, const char *screenAddress, double x, double y, const char *player) {
|
||||||
if(!nn_hasUser(computer, player)) return NN_OK;
|
if(!nn_hasUser(computer, player)) return NN_OK;
|
||||||
}
|
}
|
||||||
@@ -3149,7 +3158,7 @@ static nn_Exit nn_eepromHandler(nn_ComponentRequest *req) {
|
|||||||
}
|
}
|
||||||
if(method == NN_EENUM_GET) {
|
if(method == NN_EENUM_GET) {
|
||||||
ereq.action = NN_EEPROM_GET;
|
ereq.action = NN_EEPROM_GET;
|
||||||
char buf[eeprom.size];
|
NN_VLA(char, buf, eeprom.size);
|
||||||
ereq.buf = buf;
|
ereq.buf = buf;
|
||||||
ereq.buflen = eeprom.size;
|
ereq.buflen = eeprom.size;
|
||||||
e = state->handler(&ereq);
|
e = state->handler(&ereq);
|
||||||
@@ -3159,7 +3168,7 @@ static nn_Exit nn_eepromHandler(nn_ComponentRequest *req) {
|
|||||||
}
|
}
|
||||||
if(method == NN_EENUM_GETDATA) {
|
if(method == NN_EENUM_GETDATA) {
|
||||||
ereq.action = NN_EEPROM_GETDATA;
|
ereq.action = NN_EEPROM_GETDATA;
|
||||||
char buf[eeprom.size];
|
NN_VLA(char, buf, eeprom.size);
|
||||||
ereq.buf = buf;
|
ereq.buf = buf;
|
||||||
ereq.buflen = eeprom.size;
|
ereq.buflen = eeprom.size;
|
||||||
e = state->handler(&ereq);
|
e = state->handler(&ereq);
|
||||||
|
|||||||
@@ -9,21 +9,43 @@ extern "C" {
|
|||||||
// Used internally as well.
|
// Used internally as well.
|
||||||
// Based off https://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor
|
// Based off https://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor
|
||||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
||||||
//define something for Windows (32-bit and 64-bit, this part is common)
|
#ifndef NN_WINDOWS
|
||||||
#define NN_WINDOWS
|
#define NN_WINDOWS
|
||||||
|
#endif
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
|
#ifndef NN_MACOS
|
||||||
#define NN_MACOS
|
#define NN_MACOS
|
||||||
|
#endif
|
||||||
#elif __linux__
|
#elif __linux__
|
||||||
|
#ifndef NN_LINUX
|
||||||
#define NN_LINUX
|
#define NN_LINUX
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __unix__ // all unices not caught above
|
#if __unix__
|
||||||
// Unix
|
#ifndef NN_UNIX
|
||||||
#define NN_UNIX
|
#define NN_UNIX
|
||||||
|
#endif
|
||||||
|
#ifndef NN_POSIX
|
||||||
#define NN_POSIX
|
#define NN_POSIX
|
||||||
|
#endif
|
||||||
#elif defined(_POSIX_VERSION)
|
#elif defined(_POSIX_VERSION)
|
||||||
// POSIX
|
#ifndef NN_POSIX
|
||||||
#define NN_POSIX
|
#define NN_POSIX
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(__cplusplus)
|
||||||
|
#ifndef NN_ATOMIC_NONE
|
||||||
|
#define NN_ATOMIC_NONE
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define NN_INIT(type)
|
||||||
|
#else
|
||||||
|
#define NN_INIT(type) (type)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// every C standard header we depend on, conveniently put here
|
// every C standard header we depend on, conveniently put here
|
||||||
@@ -31,6 +53,19 @@ extern "C" {
|
|||||||
#include <stdint.h> // for intptr_t
|
#include <stdint.h> // for intptr_t
|
||||||
#include <stdbool.h> // for true, false and bool
|
#include <stdbool.h> // for true, false and bool
|
||||||
|
|
||||||
|
/* MSVC can't use VLA;
|
||||||
|
* What we see : NN_VLA(const char *, comps, len);
|
||||||
|
* What compiler see after preproccessor : const char * comps[len];
|
||||||
|
* What actaully was : const char *comps[len];
|
||||||
|
*/
|
||||||
|
// Test: gcc -E -DNN_VLA\(type,name,count\)="type name[count]" -x c - <<< 'NN_VLA(const char *, comps, len);'
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <malloc.h>
|
||||||
|
#define NN_VLA(type, name, count) type *name = (type *)_alloca(sizeof(type) * (count))
|
||||||
|
#else
|
||||||
|
#define NN_VLA(type, name, count) type name[count]
|
||||||
|
#endif
|
||||||
|
|
||||||
// Internally we need stdatomic.h and, if NN_BAREMETAL is not defined, stdlib.h and time.h
|
// Internally we need stdatomic.h and, if NN_BAREMETAL is not defined, stdlib.h and time.h
|
||||||
|
|
||||||
// The entire NeoNucleus API, in one header file
|
// The entire NeoNucleus API, in one header file
|
||||||
@@ -40,7 +75,8 @@ extern "C" {
|
|||||||
#define NN_KiB (1024)
|
#define NN_KiB (1024)
|
||||||
#define NN_MiB (1024 * NN_KiB)
|
#define NN_MiB (1024 * NN_KiB)
|
||||||
#define NN_GiB (1024 * NN_MiB)
|
#define NN_GiB (1024 * NN_MiB)
|
||||||
#define NN_TiB (1024 * NN_TiB)
|
// probably recursive: #define NN_TiB (1024 * NN_TiB)
|
||||||
|
#define NN_TiB ((size_t)1024 * NN_GiB)
|
||||||
|
|
||||||
// the alignment an allocation should have
|
// the alignment an allocation should have
|
||||||
#define NN_ALLOC_ALIGN 16
|
#define NN_ALLOC_ALIGN 16
|
||||||
|
|||||||
BIN
src/neonucleus.obj
Normal file
BIN
src/neonucleus.obj
Normal file
Binary file not shown.
Reference in New Issue
Block a user