#include "cell.h" #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #include #else #include #include #include #ifdef __linux__ #include #include #include #include #include #endif #endif #include static JSClassID js_dylib_class_id; static void js_dylib_finalizer(JSRuntime *rt, JSValue val) { void *handle = JS_GetOpaque(val, js_dylib_class_id); if (handle) { #ifdef _WIN32 FreeLibrary((HMODULE)handle); #else dlclose(handle); #endif } } static JSClassDef js_dylib_class = { "dylib", .finalizer = js_dylib_finalizer, }; JSC_CCALL(os_now, return number2js(js, (double)SDL_GetTicksNS()/1000000000.0)) JSC_CCALL(os_sleep, double secs = js2number(js,argv[0]); int ms = secs*1000; SDL_Delay(ms); ) JSC_CCALL(os_power_state, int pct, secs; SDL_PowerState state = SDL_GetPowerInfo(&secs, &pct); const char *statestr = "unknown"; switch(state) { case SDL_POWERSTATE_ON_BATTERY: statestr = "battery"; break; case SDL_POWERSTATE_NO_BATTERY: statestr = "no battery"; break; case SDL_POWERSTATE_CHARGING: statestr = "charging"; break; case SDL_POWERSTATE_CHARGED: statestr = "charged"; break; case SDL_POWERSTATE_ERROR: statestr = "error"; break; case SDL_POWERSTATE_UNKNOWN: statestr = "unknown"; break; } ret = JS_NewObject(js); JS_SetPropertyStr(js,ret,"state",JS_NewString(js,statestr)); JS_SetPropertyStr(js,ret,"percent",number2js(js,pct)); JS_SetPropertyStr(js,ret,"seconds",number2js(js,secs)); ) JSC_CCALL(os_totalmem, return number2js(js, SDL_GetSystemRAM())) JSC_CCALL(os_platform, return JS_NewString(js,SDL_GetPlatform())) static JSValue js_os_hostname(JSContext *js, JSValue self, int argc, JSValue *argv) { JSValue ret = JS_NULL; #ifdef _WIN32 TCHAR buffer[256] = TEXT(""); DWORD size = sizeof(buffer) / sizeof(TCHAR); GetComputerName(buffer, &size); return JS_NewString(js, buffer); #else struct utsname buffer; if (uname(&buffer) != 0) return JS_ThrowReferenceError(js,"Could not get hostname."); return JS_NewString(js, buffer.nodename); #endif return ret; } static JSValue js_os_arch(JSContext *js, JSValue self, int argc, JSValue *argv) { JSValue ret = JS_NULL; #if defined(__x86_64__) || defined(_M_X64) return JS_NewString(js,"x64"); #elif defined(__aarch64__) || defined(_M_ARM64) return JS_NewString(js,"arm64"); #elif defined(__arm__) || defined(_M_ARM) return JS_NewString(js,"arm"); #elif defined(__i386__) || defined(_M_IX86) return JS_NewString(js,"ia32"); #elif defined(__loongarch__) || defined(__loongarch32) || defined(__loongarch64) return JS_NewString(js,"loong64"); #elif defined(__mips__) || defined(__mips) || defined(_M_MIPS) // You might want to distinguish mips vs mipsel return JS_NewString(js,"mips"); #elif defined(__ppc64__) || defined(__powerpc64__) || defined(_M_PPC) // You might want to distinguish ppc vs ppc64, big-endian vs little-endian return JS_NewString(js,"ppc64"); #elif defined(__riscv) && __riscv_xlen == 64 return JS_NewString(js,"riscv64"); #elif defined(__s390x__) return JS_NewString(js,"s390x"); #else return JS_NewString(js,"unknown"); #endif return ret; } static JSValue js_os_freemem(JSContext *js, JSValue self, int argc, JSValue *argv) { JSValue ret = JS_NULL; #ifdef _WIN32 MEMORYSTATUSEX statex; statex.dwLength = sizeof(statex); if (!GlobalMemoryStatusEx(&statex)) return JS_ThrowInternalError(js,"GlobalMemoryStatusEx failed"); return JS_NewInt64(js,(int64_t)statex.ullAvailPhys); #elif defined(__linux__) struct sysinfo info; if (sysinfo(&info) == 0) return JS_NewInt64(js,(int64_t)info.freeram * info.mem_unit); return JS_NewInt64(js,0); #elif defined(__FreeBSD__) || defined(__OpenBSD__) // A very rough fallback using the same sysconf approach // (macOS or *BSD typically need specialized APIs to get free mem accurately) // This is often only "unused" pages, ignoring caches, etc. long pages = sysconf(_SC_AVPHYS_PAGES); long page_size = sysconf(_SC_PAGE_SIZE); if (pages < 0 || page_size < 0) return JS_NewInt64(js,0); return JS_NewInt64(js,(int64_t)pages * (int64_t)page_size); #else // Fallback: unknown return JS_NewInt64(js,0); #endif return ret; } static JSValue js_os_version(JSContext *js, JSValue self, int argc, JSValue *argv) { JSValue ret = JS_NULL; #ifdef _WIN32 typedef LONG (WINAPI *RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); HMODULE h = GetModuleHandleA("ntdll.dll"); if (h) { RtlGetVersionPtr fx = (RtlGetVersionPtr)GetProcAddress(h, "RtlGetVersion"); if (fx) { RTL_OSVERSIONINFOW ver; memset(&ver, 0, sizeof(ver)); ver.dwOSVersionInfoSize = sizeof(ver); if (!fx(&ver)) { char buf[128]; sprintf(buf, "%u.%u.%u", (unsigned)ver.dwMajorVersion, (unsigned)ver.dwMinorVersion, (unsigned)ver.dwBuildNumber ); return JS_NewString(js, buf); } } } OSVERSIONINFOW wver; memset(&wver, 0, sizeof(wver)); wver.dwOSVersionInfoSize = sizeof(wver); if (GetVersionExW(&wver)) { char buf[128]; sprintf(buf, "%u.%u.%u", (unsigned)wver.dwMajorVersion, (unsigned)wver.dwMinorVersion, (unsigned)wver.dwBuildNumber ); return JS_NewString(js, buf); } return JS_NewString(js, "Windows_Unknown"); #else struct utsname info; if (!uname(&info)) return JS_NewString(js, info.release); return JS_NewString(js, ""); #endif return ret; } JSC_CCALL(os_buffer2string, if (argc < 1) { return JS_ThrowTypeError(js, "buffer2string expects an ArrayBuffer"); } size_t len; uint8_t *buf = js_get_blob_data(js, &len, argv[0]); if (!buf) { return JS_ThrowTypeError(js, "First argument must be an ArrayBuffer"); } // Create a null-terminated string from the buffer char *str = js_malloc(js, len + 1); if (!str) { return JS_ThrowInternalError(js, "Failed to allocate memory"); } memcpy(str, buf, len); str[len] = '\0'; JSValue result = JS_NewString(js, str); js_free(js, str); return result; ) #define JSOBJ_ADD_FIELD(OBJ, STRUCT, FIELD, TYPE) \ JS_SetPropertyStr(js, OBJ, #FIELD, TYPE##2js(js,STRUCT.FIELD));\ #define JSJMEMRET(FIELD) JSOBJ_ADD_FIELD(ret, jsmem, FIELD, number) JSC_CCALL(os_mallinfo, ret = JS_NULL; /*struct mallinfo jsmem = mallinfo(); ret = JS_NewObject(js); JSJMEMRET(arena); JSJMEMRET(ordblks); JSJMEMRET(smblks); JSJMEMRET(hblks); JSJMEMRET(hblkhd); JSJMEMRET(usmblks); JSJMEMRET(fsmblks); JSJMEMRET(uordblks); JSJMEMRET(fordblks); JSJMEMRET(keepcost);*/ ) static JSValue js_os_rusage(JSContext *js, JSValue self, int argc, JSValue *argv) { JSValue ret = JS_NULL; ret = JS_NewObject(js); #if defined(__linux__) || defined(__APPLE__) struct rusage jsmem; getrusage(RUSAGE_SELF, &jsmem); JSJMEMRET(ru_maxrss); JSJMEMRET(ru_ixrss); JSJMEMRET(ru_idrss); JSJMEMRET(ru_isrss); JSJMEMRET(ru_minflt); JSJMEMRET(ru_majflt); JSJMEMRET(ru_nswap); JSJMEMRET(ru_inblock); JSJMEMRET(ru_oublock); JSJMEMRET(ru_msgsnd); JSJMEMRET(ru_msgrcv); JSJMEMRET(ru_nsignals); JSJMEMRET(ru_nvcsw); JSJMEMRET(ru_nivcsw); #endif return ret; } JSC_SCALL(os_system, int err = system(str); ret = number2js(js,err); ) JSC_SCALL(os_exit, exit(0); ) static JSValue js_os_dylib_open(JSContext *js, JSValue self, int argc, JSValue *argv) { if (argc < 1) { return JS_ThrowTypeError(js, "dylib_open requires a path argument"); } const char *path = JS_ToCString(js, argv[0]); if (!path) { return JS_ThrowTypeError(js, "path must be a string"); } void *handle; #ifdef _WIN32 handle = LoadLibraryA(path); #else handle = dlopen(path, RTLD_NOW | RTLD_LOCAL); #endif JS_FreeCString(js, path); if (!handle) { const char *error_msg = "Could not load library"; #ifndef _WIN32 const char *dl_error = dlerror(); if (dl_error) { error_msg = dl_error; } #endif return JS_ThrowReferenceError(js, "Failed to load library: %s", error_msg); } JSValue dylib_obj = JS_NewObjectClass(js, js_dylib_class_id); if (JS_IsException(dylib_obj)) { #ifdef _WIN32 FreeLibrary((HMODULE)handle); #else dlclose(handle); #endif return dylib_obj; } JS_SetOpaque(dylib_obj, handle); return dylib_obj; } static JSValue js_os_dylib_symbol(JSContext *js, JSValue self, int argc, JSValue *argv) { if (argc < 2) { return JS_ThrowTypeError(js, "dylib_symbol requires dylib object and symbol name"); } void *handle = JS_GetOpaque(argv[0], js_dylib_class_id); if (!handle) { return JS_ThrowTypeError(js, "First argument must be a dylib object"); } const char *symbol_name = JS_ToCString(js, argv[1]); if (!symbol_name) { return JS_ThrowTypeError(js, "symbol name must be a string"); } JSValue (*symbol)(JSContext *js); #ifdef _WIN32 symbol = GetProcAddress((HMODULE)handle, symbol_name); #else symbol = dlsym(handle, symbol_name); #endif JS_FreeCString(js, symbol_name); if (!symbol) { const char *error_msg = "Symbol not found"; #ifndef _WIN32 const char *dl_error = dlerror(); if (dl_error) { error_msg = dl_error; } #endif return JS_ThrowReferenceError(js, "Failed to get symbol: %s", error_msg); } // Return the symbol as a pointer value return symbol(js); } JSC_CCALL(os_print, size_t len; const char *str = JS_ToCStringLen(js, &len, argv[0]); printf("%.*s", (int)len, str); JS_FreeCString(js, str); ) static JSValue js_os_load_internal(JSContext *js, JSValue self, int argc, JSValue *argv) { void *handle; #ifdef _WIN32 handle = GetModuleHandle(NULL); #else handle = dlopen(NULL, RTLD_LAZY); #endif if (argc < 1) return JS_ThrowTypeError(js, "load_internal requires a symbol name"); const char *symbol_name = JS_ToCString(js, argv[0]); if (!symbol_name) return JS_ThrowTypeError(js, "symbol name must be a string"); JSValue (*symbol)(JSContext *js); #if defined(_WIN32) symbol = GetProcAddress((HMODULE)handle, symbol_name); #else symbol = dlsym(handle, symbol_name); #endif JS_FreeCString(js, symbol_name); if (!symbol) return JS_NULL; return symbol(js); } #if defined(_WIN32) // ------- Windows: use BCryptGenRandom ------- int randombytes(void *buf, size_t n) { NTSTATUS status = BCryptGenRandom(NULL, (PUCHAR)buf, (ULONG)n, BCRYPT_USE_SYSTEM_PREFERRED_RNG); return (status == 0) ? 0 : -1; } #elif defined(__linux__) // ------- Linux: try getrandom, fall back to /dev/urandom ------- static int randombytes_fallback(void *buf, size_t n) { int fd = open("/dev/urandom", O_RDONLY); if (fd < 0) return -1; ssize_t r = read(fd, buf, n); close(fd); return (r == (ssize_t)n) ? 0 : -1; } int randombytes(void *buf, size_t n) { #ifdef SYS_getrandom // Try getrandom(2) if available ssize_t ret = syscall(SYS_getrandom, buf, n, 0); if (ret < 0) { // If getrandom is not supported or fails, fall back if (errno == ENOSYS) { return randombytes_fallback(buf, n); } return -1; } return (ret == (ssize_t)n) ? 0 : -1; #else // getrandom not available, just fallback return randombytes_fallback(buf, n); #endif } #else // ------- Other Unix: read from /dev/urandom ------- static int rand_fd = -1; int randombytes(void *buf, size_t n) { if (rand_fd < 0) { rand_fd = open("/dev/urandom", O_RDONLY); if (rand_fd < 0) return -1; } ssize_t r = read(rand_fd, buf, n); return (r == (ssize_t)n) ? 0 : -1; } #endif JSC_CCALL(os_random, double random_double; uint8_t *buf = (uint8_t *)&random_double; if (randombytes(buf, sizeof(double)) != 0) { return JS_ThrowInternalError(js, "failed to generate random bytes"); } return JS_NewFloat64(js, random_double); ) static const JSCFunctionListEntry js_os_funcs[] = { MIST_FUNC_DEF(os, platform, 0), MIST_FUNC_DEF(os, arch, 0), MIST_FUNC_DEF(os, totalmem, 0), MIST_FUNC_DEF(os, freemem, 0), MIST_FUNC_DEF(os, hostname, 0), MIST_FUNC_DEF(os, version, 0), MIST_FUNC_DEF(os, now, 0), MIST_FUNC_DEF(os, power_state, 0), MIST_FUNC_DEF(os, rusage, 0), MIST_FUNC_DEF(os, mallinfo, 0), MIST_FUNC_DEF(os, buffer2string, 1), MIST_FUNC_DEF(os, system, 1), MIST_FUNC_DEF(os, exit, 0), MIST_FUNC_DEF(os, sleep, 1), MIST_FUNC_DEF(os, dylib_open, 1), MIST_FUNC_DEF(os, dylib_symbol, 2), MIST_FUNC_DEF(os, load_internal, 1), MIST_FUNC_DEF(os, print, 1), MIST_FUNC_DEF(os, random, 0), }; JSValue js_os_use(JSContext *js) { JS_NewClassID(&js_dylib_class_id); JS_NewClass(JS_GetRuntime(js), js_dylib_class_id, &js_dylib_class); JSValue mod = JS_NewObject(js); JS_SetPropertyFunctionList(js,mod,js_os_funcs,countof(js_os_funcs)); return mod; }