namespace Slime { inline proc get_cwd() -> char* { const u32 buf_size = 2048; char* res = (char*)malloc(buf_size * sizeof(char)); #ifdef _MSC_VER _getcwd(res, buf_size); #else getcwd(res, buf_size); #endif return res; } inline proc change_cwd(char* dir) -> void { #ifdef _MSC_VER _chdir(dir); #else chdir(dir); #endif } inline proc duplicate_c_string(const char* str) -> char* { #ifdef _MSC_VER return _strdup(str); #else return strdup(str); #endif } #ifdef _MSC_VER s32 vasprintf(char **strp, const char *fmt, va_list ap) { // _vscprintf tells you how big the buffer needs to be s32 len = _vscprintf(fmt, ap); if (len == -1) { return -1; } size_t size = (size_t)len + 1; char *str = (char*)malloc(size); if (!str) { return -1; } // _vsprintf_s is the "secure" version of vsprintf s32 r = vsprintf_s(str, len + 1, fmt, ap); if (r == -1) { free(str); return -1; } *strp = str; return r; } s32 asprintf(char **strp, const char *fmt, ...) { va_list ap; va_start(ap, fmt); s32 r = vasprintf(strp, fmt, ap); va_end(ap); return r; } #endif proc get_exe_dir() -> path_char* { #ifdef _MSC_VER DWORD last_error; DWORD result; DWORD path_size = MAX_PATH; path_char* path = (path_char*)malloc(sizeof(path_char)*path_size); while (true) { memset(path, 0, path_size); result = GetModuleFileName(0, path, path_size - 1); last_error = GetLastError(); if (0 == result) { free(path); path = 0; break; } else if (result == path_size - 1) { free(path); /* May need to also check for ERROR_SUCCESS here if XP/2K */ if (ERROR_INSUFFICIENT_BUFFER != last_error) { path = 0; break; } path_size = path_size * 2; path = (path_char*)malloc((sizeof(path_char)) * path_size); } else break; } if (!path) { fprintf(stderr, "Failure: %ld\n", last_error); return nullptr; } else { // remove the exe name, so we are only left with the path s32 index_in_path = -1; s32 last_backslash = -1; path_char c; while ((c = path[++index_in_path]) != '\0') { if (c == '\\') last_backslash = index_in_path; } // we are assuming there are some backslashes path[last_backslash+1] = '\0'; return path; } #else ssize_t size = 512, i, n; char *path, *temp; while (1) { size_t used; path = (char*)malloc(size); if (!path) { errno = ENOMEM; return NULL; } used = readlink("/proc/self/exe", path, size); if (used == -1) { const s32 saved_errno = errno; free(path); errno = saved_errno; return NULL; } else if (used < 1) { free(path); errno = EIO; return NULL; } if ((size_t)used >= size) { free(path); size = (size | 2047) + 2049; continue; } size = (size_t)used; break; } /* Find final slash. */ n = 0; for (i = 0; i < size; i++) if (path[i] == '/') n = i; /* Optimize allocated size, ensuring there is room for a final slash and a string-terminating '\0', */ temp = path; path = (char*)realloc(temp, n + 2); if (!path) { free(temp); errno = ENOMEM; return NULL; } /* and properly trim and terminate the path string. */ path[n+0] = '/'; path[n+1] = '\0'; return path; #endif } }