/* * Copyright (c) 2012-2017 Daniele Bartolini and individual contributors. * License: https://github.com/dbartolini/crown/blob/master/LICENSE */ #include "core/containers/vector.h" #include "core/error/error.h" #include "core/memory/temp_allocator.h" #include "core/os.h" #include "core/platform.h" #include "core/strings/dynamic_string.h" #include "core/strings/string_stream.h" #include // strcmp #include // stat, mkdir #if CROWN_PLATFORM_POSIX #include // opendir, readdir #include // dlopen, dlclose, dlsym #include #include // fputs #include // getenv #include // memset #include // wait #include // clock_gettime #include // unlink, rmdir, getcwd, fork, execv #elif CROWN_PLATFORM_WINDOWS #include #include #include #endif #if CROWN_PLATFORM_ANDROID #include #endif namespace crown { namespace os { s64 clocktime() { #if CROWN_PLATFORM_LINUX || CROWN_PLATFORM_ANDROID timespec now; clock_gettime(CLOCK_MONOTONIC, &now); return now.tv_sec * s64(1000000000) + now.tv_nsec; #elif CROWN_PLATFORM_OSX struct timeval now; gettimeofday(&now, NULL); return now.tv_sec * s64(1000000) + now.tv_usec; #elif CROWN_PLATFORM_WINDOWS LARGE_INTEGER ttime; QueryPerformanceCounter(&ttime); return (s64)ttime.QuadPart; #endif } s64 clockfrequency() { #if CROWN_PLATFORM_LINUX || CROWN_PLATFORM_ANDROID return s64(1000000000); #elif CROWN_PLATFORM_OSX return s64(1000000); #elif CROWN_PLATFORM_WINDOWS LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); return (s64)freq.QuadPart; #endif } /// Suspends execution for @a ms milliseconds. void sleep(u32 ms) { #if CROWN_PLATFORM_POSIX usleep(ms * 1000); #elif CROWN_PLATFORM_WINDOWS Sleep(ms); #endif } /// Opens the library at @a path. void* library_open(const char* path) { #if CROWN_PLATFORM_POSIX return ::dlopen(path, RTLD_LAZY); #elif CROWN_PLATFORM_WINDOWS return (void*)LoadLibraryA(path); #endif } /// Closes a @a library previously opened by library_open. void library_close(void* library) { #if CROWN_PLATFORM_POSIX dlclose(library); #elif CROWN_PLATFORM_WINDOWS FreeLibrary((HMODULE)library); #endif } /// Returns a pointer to the symbol @a name in the given @a library. void* library_symbol(void* library, const char* name) { #if CROWN_PLATFORM_POSIX return ::dlsym(library, name); #elif CROWN_PLATFORM_WINDOWS return (void*)GetProcAddress((HMODULE)library, name); #endif } /// Logs the message @a msg. void log(const char* msg) { #if CROWN_PLATFORM_ANDROID __android_log_write(ANDROID_LOG_DEBUG, "crown", msg); #elif CROWN_PLATFORM_WINDOWS OutputDebugStringA(msg); #else fputs(msg, stdout); fflush(stdout); #endif } void stat(Stat& info, const char* path) { info.file_type = Stat::NO_ENTRY; info.size = 0; info.mtime = 0; #if CROWN_PLATFORM_POSIX struct stat buf; memset(&buf, 0, sizeof(buf)); int err = ::stat(path, &buf); if (err != 0) return; if (S_ISREG(buf.st_mode) == 1) info.file_type = Stat::REGULAR; else if (S_ISDIR(buf.st_mode) == 1) info.file_type = Stat::DIRECTORY; #elif CROWN_PLATFORM_WINDOWS struct _stat64 buf; int err = ::_stat64(path, &buf); if (err != 0) return; if ((buf.st_mode & _S_IFREG) != 0) info.file_type = Stat::REGULAR; else if ((buf.st_mode & _S_IFDIR) != 0) info.file_type = Stat::DIRECTORY; #endif info.size = buf.st_size; info.mtime = buf.st_mtime; } /// Deletes the file at @a path. void delete_file(const char* path) { #if CROWN_PLATFORM_POSIX int err = ::unlink(path); CE_ASSERT(err == 0, "unlink: errno = %d", errno); CE_UNUSED(err); #elif CROWN_PLATFORM_WINDOWS BOOL err = DeleteFile(path); CE_ASSERT(err != 0, "DeleteFile: GetLastError = %d", GetLastError()); CE_UNUSED(err); #endif } /// Creates a directory named @a path. void create_directory(const char* path) { #if CROWN_PLATFORM_POSIX int err = ::mkdir(path, 0755); CE_ASSERT(err == 0, "mkdir: errno = %d", errno); CE_UNUSED(err); #elif CROWN_PLATFORM_WINDOWS BOOL err = CreateDirectory(path, NULL); CE_ASSERT(err != 0, "CreateDirectory: GetLastError = %d", GetLastError()); CE_UNUSED(err); #endif } /// Deletes the directory at @a path. void delete_directory(const char* path) { #if CROWN_PLATFORM_POSIX int err = ::rmdir(path); CE_ASSERT(err == 0, "rmdir: errno = %d", errno); CE_UNUSED(err); #elif CROWN_PLATFORM_WINDOWS BOOL err = RemoveDirectory(path); CE_ASSERT(err != 0, "RemoveDirectory: GetLastError = %d", GetLastError()); CE_UNUSED(err); #endif } /// Returns the list of @a files at the given @a path. void list_files(const char* path, Vector& files); /// Returns the current working directory. const char* getcwd(char* buf, u32 size) { #if CROWN_PLATFORM_POSIX return ::getcwd(buf, size); #elif CROWN_PLATFORM_WINDOWS GetCurrentDirectory(size, buf); return buf; #endif } /// Returns the value of the environment variable @a name. const char* getenv(const char* name) { #if CROWN_PLATFORM_POSIX return ::getenv(name); #elif CROWN_PLATFORM_WINDOWS // GetEnvironmentVariable(name, buf, size); return NULL; #endif } void list_files(const char* path, Vector& files) { #if CROWN_PLATFORM_POSIX DIR *dir; struct dirent *entry; if (!(dir = opendir(path))) return; while ((entry = readdir(dir))) { const char* dname = entry->d_name; if (!strcmp(dname, ".") || !strcmp(dname, "..")) continue; TempAllocator512 ta; DynamicString fname(ta); fname.set(dname, strlen32(dname)); vector::push_back(files, fname); } closedir(dir); #elif CROWN_PLATFORM_WINDOWS TempAllocator1024 ta; DynamicString cur_path(ta); cur_path += path; cur_path += "\\*"; WIN32_FIND_DATA ffd; HANDLE file = FindFirstFile(cur_path.c_str(), &ffd); if (file == INVALID_HANDLE_VALUE) return; do { const char* dname = ffd.cFileName; if (!strcmp(dname, ".") || !strcmp(dname, "..")) continue; TempAllocator512 ta; DynamicString fname(ta); fname.set(dname, strlen32(dname)); vector::push_back(files, fname); } while (FindNextFile(file, &ffd) != 0); FindClose(file); #endif } int execute_process(const char* const* argv, StringStream& output) { TempAllocator512 ta; StringStream path(ta); path << argv[0]; path << ' '; #if CROWN_PLATFORM_POSIX path << "2>&1 "; #endif for (s32 i = 1; argv[i] != NULL; ++i) { const char* arg = argv[i]; for (; *arg; ++arg) { if (*arg == ' ') path << '\\'; path << *arg; } path << ' '; } #if CROWN_PLATFORM_POSIX FILE* file = popen(string_stream::c_str(path), "r"); char buf[1024]; while (fgets(buf, sizeof(buf), file) != NULL) output << buf; return pclose(file); #elif CROWN_PLATFORM_WINDOWS STARTUPINFO info; memset(&info, 0, sizeof(info)); info.cb = sizeof(info); PROCESS_INFORMATION process; memset(&process, 0, sizeof(process)); int err = CreateProcess(argv[0] , (LPSTR)string_stream::c_str(path) , NULL , NULL , FALSE , 0 , NULL , NULL , &info , &process ); CE_ASSERT(err != 0, "CreateProcess: GetLastError = %d", GetLastError()); CE_UNUSED(err); DWORD exitcode = 1; ::WaitForSingleObject(process.hProcess, INFINITE); GetExitCodeProcess(process.hProcess, &exitcode); CloseHandle(process.hProcess); CloseHandle(process.hThread); return (int)exitcode; #endif } } // namespace os } // namespace crown