#include "filesystem.h" #ifndef NOMINMAX #define NOMINMAX #endif #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include // Basic begin void *VReserve(size_t size) { void *result = (uint8_t *)VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE); return result; } bool VCommit(void *p, size_t size) { void *result = VirtualAlloc(p, size, MEM_COMMIT, PAGE_READWRITE); return result ? true : false; } bool VRelease(void *p) { BOOL result = VirtualFree(p, 0, MEM_RELEASE); return result ? true : false; } bool VDecommit(void *p, size_t size) { BOOL result = VirtualFree(p, size, MEM_DECOMMIT); return result ? true : false; } // Basic end Process RunEx(String args) { Scratch scratch; wchar_t *application_name = NULL; wchar_t *cmd = ToWidechar(scratch, args); BOOL inherit_handles = FALSE; DWORD creation_flags = 0; void *enviroment = NULL; wchar_t *working_dir = NULL; STARTUPINFOW startup_info = {}; startup_info.cb = sizeof(STARTUPINFOW); Process result = {}; Assert(sizeof(result.platform) >= sizeof(PROCESS_INFORMATION)); PROCESS_INFORMATION *process_info = (PROCESS_INFORMATION *)result.platform; BOOL success = CreateProcessW(application_name, cmd, NULL, NULL, inherit_handles, creation_flags, enviroment, working_dir, &startup_info, process_info); result.is_valid = true; if (!success) { result.is_valid = false; LPVOID lpMsgBuf; DWORD dw = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL); LocalFree(lpMsgBuf); printf("Failed to create process \ncmd: %.*s\nwindows_message: %s", FmtString(args), (char *)lpMsgBuf); Assert(!"Failed to create process"); } return result; } int Wait(Process *process) { Assert(process->is_valid); PROCESS_INFORMATION *pi = (PROCESS_INFORMATION *)process->platform; WaitForSingleObject(pi->hProcess, INFINITE); DWORD exit_code; BOOL err = GetExitCodeProcess(pi->hProcess, &exit_code); Assert(err != 0); CloseHandle(pi->hProcess); CloseHandle(pi->hThread); process[0] = {}; return (int)exit_code; } bool InitOS() { SetConsoleOutputCP(CP_UTF8); HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); if (hOut != INVALID_HANDLE_VALUE) { DWORD dwMode = 0; if (GetConsoleMode(hOut, &dwMode)) { dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; if (SetConsoleMode(hOut, dwMode)) { return true; } else { printf("Failed to enable colored terminal output C\n"); } } else { printf("Failed to enable colored terminal output B\n"); } } else { printf("Failed to enable colored terminal output A\n"); } return false; } String ReadFile(Allocator arena, String path) { bool success = false; String result = {}; wchar_t wpath[1024]; CreateWidecharFromChar(wpath, Lengthof(wpath), path.data, path.len); HANDLE handle = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (handle != INVALID_HANDLE_VALUE) { LARGE_INTEGER file_size; if (GetFileSizeEx(handle, &file_size)) { if (file_size.QuadPart != 0) { result.len = (int64_t)file_size.QuadPart; result.data = (char *)AllocSize(arena, result.len + 1); DWORD read; if (ReadFile(handle, result.data, (DWORD)result.len, &read, NULL)) { // @todo: can only read 32 byte size files? if (read == result.len) { success = true; result.data[result.len] = 0; } } } } CloseHandle(handle); } if (!success) { Dealloc(arena, &result.data); result = {}; } return result; } typedef struct Win32_FileIter { HANDLE handle; WIN32_FIND_DATAW data; } Win32_FileIter; String GetAbsolutePath(Allocator arena, String relative) { wchar_t wpath[1024]; CreateWidecharFromChar(wpath, Lengthof(wpath), relative.data, relative.len); wchar_t wpath_abs[1024]; DWORD written = GetFullPathNameW((wchar_t *)wpath, Lengthof(wpath_abs), wpath_abs, 0); if (written == 0) return {}; String path = ToString(arena, {(wchar_t *)wpath_abs, written}); NormalizePathInPlace(path); return path; } bool IsValid(const FileIter &it) { return it.is_valid; } void Advance(FileIter *it) { if (it->temp.arena) EndTemp(it->temp); it->temp = BeginTemp(it->arena); while (FindNextFileW(it->w32->handle, &it->w32->data) != 0) { WIN32_FIND_DATAW *data = &it->w32->data; // Skip '.' and '..' if (data->cFileName[0] == '.' && data->cFileName[1] == '.' && data->cFileName[2] == 0) continue; if (data->cFileName[0] == '.' && data->cFileName[1] == 0) continue; it->is_directory = data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; it->filename = ToString(*it->arena, (wchar_t *)data->cFileName, WideLength(data->cFileName)); const char *is_dir = it->is_directory ? "/" : ""; const char *separator = it->path.data[it->path.len - 1] == '/' ? "" : "/"; it->relative_path = Format(*it->arena, "%.*s%s%.*s%s", FmtString(it->path), separator, FmtString(it->filename), is_dir); it->absolute_path = GetAbsolutePath(*it->arena, it->relative_path); it->is_valid = true; if (it->is_directory) { Assert(it->relative_path.data[it->relative_path.len - 1] == '/'); Assert(it->absolute_path.data[it->absolute_path.len - 1] == '/'); } return; } it->is_valid = false; DWORD error = GetLastError(); Assert(error == ERROR_NO_MORE_FILES); FindClose(it->w32->handle); Dealloc(it->allocator, &it->arena); } FileIter IterateFiles(Allocator alo, String path) { FileIter it = {0}; it.allocator = alo; it.arena = AllocArena(alo, MiB(2)); it.path = path; String modified_path = Format(*it.arena, "%.*s\\*", FmtString(path)); String16 modified_path16 = ToString16(*it.arena, modified_path); it.w32 = AllocType(*it.arena, Win32_FileIter); it.w32->handle = FindFirstFileW(modified_path16.data, &it.w32->data); if (it.w32->handle == INVALID_HANDLE_VALUE) { it.is_valid = false; return it; } Advance(&it); return it; } #if _WIN32 #include double get_time_in_micros(void) { static double invfreq; if (!invfreq) { LARGE_INTEGER frequency; QueryPerformanceFrequency(&frequency); invfreq = 1000000.0 / frequency.QuadPart; } LARGE_INTEGER counter; QueryPerformanceCounter(&counter); return counter.QuadPart * invfreq; } #else #include double get_time_in_micros(void) { struct timespec spec; clock_gettime(CLOCK_MONOTONIC, &spec); return (((double)spec.tv_sec) * 1000000) + (((double)spec.tv_nsec) / 1000); } #endif