/* * Copyright (c) 2013 Hugh Bailey * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include "base.h" #include "platform.h" #include "dstr.h" #include "../../deps/w32-pthreads/pthread.h" static bool have_clockfreq = false; static LARGE_INTEGER clock_freq; static uint32_t winver = 0; static inline uint64_t get_clockfreq(void) { if (!have_clockfreq) QueryPerformanceFrequency(&clock_freq); return clock_freq.QuadPart; } static inline uint32_t get_winver(void) { if (!winver) { OSVERSIONINFO osvi; memset(&osvi, 0, sizeof(osvi)); winver = (osvi.dwMajorVersion << 16) | (osvi.dwMinorVersion); } return winver; } void *os_dlopen(const char *path) { struct dstr dll_name; wchar_t *wpath; HMODULE h_library = NULL; if (!path) return NULL; dstr_init_copy(&dll_name, path); if (!dstr_find(&dll_name, ".dll")) dstr_cat(&dll_name, ".dll"); os_utf8_to_wcs_ptr(dll_name.array, 0, &wpath); h_library = LoadLibraryW(wpath); bfree(wpath); dstr_free(&dll_name); if (!h_library) blog(LOG_INFO, "LoadLibrary failed for '%s', error: %u", path, GetLastError()); return h_library; } void *os_dlsym(void *module, const char *func) { void *handle; handle = (void*)GetProcAddress(module, func); return handle; } void os_dlclose(void *module) { FreeLibrary(module); } bool os_sleepto_ns(uint64_t time_target) { uint64_t t = os_gettime_ns(); uint32_t milliseconds; if (t >= time_target) return false; milliseconds = (uint32_t)((time_target - t)/1000000); if (milliseconds > 1) Sleep(milliseconds-1); for (;;) { t = os_gettime_ns(); if (t >= time_target) return true; #if 1 Sleep(1); #else Sleep(0); #endif } } void os_sleep_ms(uint32_t duration) { /* windows 8+ appears to have decreased sleep precision */ if (get_winver() >= 0x0602 && duration > 0) duration--; Sleep(duration); } uint64_t os_gettime_ns(void) { LARGE_INTEGER current_time; double time_val; QueryPerformanceCounter(¤t_time); time_val = (double)current_time.QuadPart; time_val *= 1000000000.0; time_val /= (double)get_clockfreq(); return (uint64_t)time_val; } /* returns %appdata%\[name] on windows */ char *os_get_config_path(const char *name) { char *ptr; wchar_t path_utf16[MAX_PATH]; struct dstr path; SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, path_utf16); os_wcs_to_utf8_ptr(path_utf16, 0, &ptr); dstr_init_move_array(&path, ptr); dstr_cat(&path, "\\"); dstr_cat(&path, name); return path.array; } bool os_file_exists(const char *path) { WIN32_FIND_DATAW wfd; HANDLE hFind; wchar_t *path_utf16; if (!os_utf8_to_wcs_ptr(path, 0, &path_utf16)) return false; hFind = FindFirstFileW(path_utf16, &wfd); if (hFind != INVALID_HANDLE_VALUE) FindClose(hFind); bfree(path_utf16); return hFind != INVALID_HANDLE_VALUE; } struct os_dir { HANDLE handle; WIN32_FIND_DATA wfd; bool first; struct os_dirent out; }; os_dir_t os_opendir(const char *path) { struct dstr path_str = {0}; struct os_dir *dir = NULL; WIN32_FIND_DATA wfd; HANDLE handle; wchar_t *w_path; dstr_copy(&path_str, path); dstr_cat(&path_str, "/*.*"); if (os_utf8_to_wcs_ptr(path_str.array, path_str.len, &w_path) > 0) { handle = FindFirstFileW(w_path, &wfd); if (handle != INVALID_HANDLE_VALUE) { dir = bzalloc(sizeof(struct os_dir)); dir->handle = handle; dir->first = true; dir->wfd = wfd; } bfree(w_path); } dstr_free(&path_str); return dir; } struct os_dirent *os_readdir(os_dir_t dir) { if (!dir) return NULL; if (dir->first) { dir->first = false; } else { if (!FindNextFileW(dir->handle, &dir->wfd)) return NULL; } os_wcs_to_utf8(dir->wfd.cFileName, 255, dir->out.d_name); dir->out.directory = !!(dir->wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); return &dir->out; } void os_closedir(os_dir_t dir) { if (dir) { FindClose(dir->handle); bfree(dir); } } int os_unlink(const char *path) { wchar_t *w_path; bool success; os_utf8_to_wcs_ptr(path, 0, &w_path); if (!w_path) return -1; success = !!DeleteFileW(w_path); bfree(w_path); return success ? 0 : -1; } int os_mkdir(const char *path) { wchar_t *path_utf16; BOOL success; if (!os_utf8_to_wcs_ptr(path, 0, &path_utf16)) return MKDIR_ERROR; success = CreateDirectory(path_utf16, NULL); bfree(path_utf16); if (!success) return (GetLastError() == ERROR_ALREADY_EXISTS) ? MKDIR_EXISTS : MKDIR_ERROR; return MKDIR_SUCCESS; } BOOL WINAPI DllMain(HINSTANCE hinst_dll, DWORD reason, LPVOID reserved) { switch (reason) { case DLL_PROCESS_ATTACH: timeBeginPeriod(1); #ifdef PTW32_STATIC_LIB pthread_win32_process_attach_np(); #endif break; case DLL_PROCESS_DETACH: timeEndPeriod(1); #ifdef PTW32_STATIC_LIB pthread_win32_process_detach_np(); #endif break; case DLL_THREAD_ATTACH: #ifdef PTW32_STATIC_LIB pthread_win32_thread_attach_np(); #endif break; case DLL_THREAD_DETACH: #ifdef PTW32_STATIC_LIB pthread_win32_thread_detach_np(); #endif break; } return true; }