os.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /*
  2. * Copyright (c) 2012-2017 Daniele Bartolini and individual contributors.
  3. * License: https://github.com/dbartolini/crown/blob/master/LICENSE
  4. */
  5. #include "core/containers/vector.h"
  6. #include "core/error/error.h"
  7. #include "core/memory/temp_allocator.h"
  8. #include "core/os.h"
  9. #include "core/platform.h"
  10. #include "core/strings/dynamic_string.h"
  11. #include "core/strings/string_stream.h"
  12. #include <string.h> // strcmp
  13. #include <sys/stat.h> // stat, mkdir
  14. #if CROWN_PLATFORM_POSIX
  15. #include <dirent.h> // opendir, readdir
  16. #include <dlfcn.h> // dlopen, dlclose, dlsym
  17. #include <errno.h>
  18. #include <stdio.h> // fputs
  19. #include <stdlib.h> // getenv
  20. #include <string.h> // memset
  21. #include <sys/wait.h> // wait
  22. #include <time.h> // clock_gettime
  23. #include <unistd.h> // unlink, rmdir, getcwd, fork, execv
  24. #elif CROWN_PLATFORM_WINDOWS
  25. #include <io.h>
  26. #include <stdio.h>
  27. #include <windows.h>
  28. #endif
  29. #if CROWN_PLATFORM_ANDROID
  30. #include <android/log.h>
  31. #endif
  32. namespace crown
  33. {
  34. namespace os
  35. {
  36. s64 clocktime()
  37. {
  38. #if CROWN_PLATFORM_LINUX || CROWN_PLATFORM_ANDROID
  39. timespec now;
  40. clock_gettime(CLOCK_MONOTONIC, &now);
  41. return now.tv_sec * s64(1000000000) + now.tv_nsec;
  42. #elif CROWN_PLATFORM_OSX
  43. struct timeval now;
  44. gettimeofday(&now, NULL);
  45. return now.tv_sec * s64(1000000) + now.tv_usec;
  46. #elif CROWN_PLATFORM_WINDOWS
  47. LARGE_INTEGER ttime;
  48. QueryPerformanceCounter(&ttime);
  49. return (s64)ttime.QuadPart;
  50. #endif
  51. }
  52. s64 clockfrequency()
  53. {
  54. #if CROWN_PLATFORM_LINUX || CROWN_PLATFORM_ANDROID
  55. return s64(1000000000);
  56. #elif CROWN_PLATFORM_OSX
  57. return s64(1000000);
  58. #elif CROWN_PLATFORM_WINDOWS
  59. LARGE_INTEGER freq;
  60. QueryPerformanceFrequency(&freq);
  61. return (s64)freq.QuadPart;
  62. #endif
  63. }
  64. /// Suspends execution for @a ms milliseconds.
  65. void sleep(u32 ms)
  66. {
  67. #if CROWN_PLATFORM_POSIX
  68. usleep(ms * 1000);
  69. #elif CROWN_PLATFORM_WINDOWS
  70. Sleep(ms);
  71. #endif
  72. }
  73. /// Opens the library at @a path.
  74. void* library_open(const char* path)
  75. {
  76. #if CROWN_PLATFORM_POSIX
  77. return ::dlopen(path, RTLD_LAZY);
  78. #elif CROWN_PLATFORM_WINDOWS
  79. return (void*)LoadLibraryA(path);
  80. #endif
  81. }
  82. /// Closes a @a library previously opened by library_open.
  83. void library_close(void* library)
  84. {
  85. #if CROWN_PLATFORM_POSIX
  86. dlclose(library);
  87. #elif CROWN_PLATFORM_WINDOWS
  88. FreeLibrary((HMODULE)library);
  89. #endif
  90. }
  91. /// Returns a pointer to the symbol @a name in the given @a library.
  92. void* library_symbol(void* library, const char* name)
  93. {
  94. #if CROWN_PLATFORM_POSIX
  95. return ::dlsym(library, name);
  96. #elif CROWN_PLATFORM_WINDOWS
  97. return (void*)GetProcAddress((HMODULE)library, name);
  98. #endif
  99. }
  100. /// Logs the message @a msg.
  101. void log(const char* msg)
  102. {
  103. #if CROWN_PLATFORM_ANDROID
  104. __android_log_write(ANDROID_LOG_DEBUG, "crown", msg);
  105. #elif CROWN_PLATFORM_WINDOWS
  106. OutputDebugStringA(msg);
  107. #else
  108. fputs(msg, stdout);
  109. fflush(stdout);
  110. #endif
  111. }
  112. void stat(Stat& info, const char* path)
  113. {
  114. info.file_type = Stat::NO_ENTRY;
  115. info.size = 0;
  116. info.mtime = 0;
  117. #if CROWN_PLATFORM_POSIX
  118. struct stat buf;
  119. memset(&buf, 0, sizeof(buf));
  120. int err = ::stat(path, &buf);
  121. if (err != 0)
  122. return;
  123. if (S_ISREG(buf.st_mode) == 1)
  124. info.file_type = Stat::REGULAR;
  125. else if (S_ISDIR(buf.st_mode) == 1)
  126. info.file_type = Stat::DIRECTORY;
  127. #elif CROWN_PLATFORM_WINDOWS
  128. struct _stat64 buf;
  129. int err = ::_stat64(path, &buf);
  130. if (err != 0)
  131. return;
  132. if ((buf.st_mode & _S_IFREG) != 0)
  133. info.file_type = Stat::REGULAR;
  134. else if ((buf.st_mode & _S_IFDIR) != 0)
  135. info.file_type = Stat::DIRECTORY;
  136. #endif
  137. info.size = buf.st_size;
  138. info.mtime = buf.st_mtime;
  139. }
  140. /// Deletes the file at @a path.
  141. void delete_file(const char* path)
  142. {
  143. #if CROWN_PLATFORM_POSIX
  144. int err = ::unlink(path);
  145. CE_ASSERT(err == 0, "unlink: errno = %d", errno);
  146. CE_UNUSED(err);
  147. #elif CROWN_PLATFORM_WINDOWS
  148. BOOL err = DeleteFile(path);
  149. CE_ASSERT(err != 0, "DeleteFile: GetLastError = %d", GetLastError());
  150. CE_UNUSED(err);
  151. #endif
  152. }
  153. /// Creates a directory named @a path.
  154. void create_directory(const char* path)
  155. {
  156. #if CROWN_PLATFORM_POSIX
  157. int err = ::mkdir(path, 0755);
  158. CE_ASSERT(err == 0, "mkdir: errno = %d", errno);
  159. CE_UNUSED(err);
  160. #elif CROWN_PLATFORM_WINDOWS
  161. BOOL err = CreateDirectory(path, NULL);
  162. CE_ASSERT(err != 0, "CreateDirectory: GetLastError = %d", GetLastError());
  163. CE_UNUSED(err);
  164. #endif
  165. }
  166. /// Deletes the directory at @a path.
  167. void delete_directory(const char* path)
  168. {
  169. #if CROWN_PLATFORM_POSIX
  170. int err = ::rmdir(path);
  171. CE_ASSERT(err == 0, "rmdir: errno = %d", errno);
  172. CE_UNUSED(err);
  173. #elif CROWN_PLATFORM_WINDOWS
  174. BOOL err = RemoveDirectory(path);
  175. CE_ASSERT(err != 0, "RemoveDirectory: GetLastError = %d", GetLastError());
  176. CE_UNUSED(err);
  177. #endif
  178. }
  179. /// Returns the list of @a files at the given @a path.
  180. void list_files(const char* path, Vector<DynamicString>& files);
  181. /// Returns the current working directory.
  182. const char* getcwd(char* buf, u32 size)
  183. {
  184. #if CROWN_PLATFORM_POSIX
  185. return ::getcwd(buf, size);
  186. #elif CROWN_PLATFORM_WINDOWS
  187. GetCurrentDirectory(size, buf);
  188. return buf;
  189. #endif
  190. }
  191. /// Returns the value of the environment variable @a name.
  192. const char* getenv(const char* name)
  193. {
  194. #if CROWN_PLATFORM_POSIX
  195. return ::getenv(name);
  196. #elif CROWN_PLATFORM_WINDOWS
  197. // GetEnvironmentVariable(name, buf, size);
  198. return NULL;
  199. #endif
  200. }
  201. void list_files(const char* path, Vector<DynamicString>& files)
  202. {
  203. #if CROWN_PLATFORM_POSIX
  204. DIR *dir;
  205. struct dirent *entry;
  206. if (!(dir = opendir(path)))
  207. return;
  208. while ((entry = readdir(dir)))
  209. {
  210. const char* dname = entry->d_name;
  211. if (!strcmp(dname, ".") || !strcmp(dname, ".."))
  212. continue;
  213. TempAllocator512 ta;
  214. DynamicString fname(ta);
  215. fname.set(dname, strlen32(dname));
  216. vector::push_back(files, fname);
  217. }
  218. closedir(dir);
  219. #elif CROWN_PLATFORM_WINDOWS
  220. TempAllocator1024 ta;
  221. DynamicString cur_path(ta);
  222. cur_path += path;
  223. cur_path += "\\*";
  224. WIN32_FIND_DATA ffd;
  225. HANDLE file = FindFirstFile(cur_path.c_str(), &ffd);
  226. if (file == INVALID_HANDLE_VALUE)
  227. return;
  228. do
  229. {
  230. const char* dname = ffd.cFileName;
  231. if (!strcmp(dname, ".") || !strcmp(dname, ".."))
  232. continue;
  233. TempAllocator512 ta;
  234. DynamicString fname(ta);
  235. fname.set(dname, strlen32(dname));
  236. vector::push_back(files, fname);
  237. }
  238. while (FindNextFile(file, &ffd) != 0);
  239. FindClose(file);
  240. #endif
  241. }
  242. int execute_process(const char* const* argv, StringStream& output)
  243. {
  244. TempAllocator512 ta;
  245. StringStream path(ta);
  246. path << argv[0];
  247. path << ' ';
  248. #if CROWN_PLATFORM_POSIX
  249. path << "2>&1 ";
  250. #endif
  251. for (s32 i = 1; argv[i] != NULL; ++i)
  252. {
  253. const char* arg = argv[i];
  254. for (; *arg; ++arg)
  255. {
  256. if (*arg == ' ')
  257. path << '\\';
  258. path << *arg;
  259. }
  260. path << ' ';
  261. }
  262. #if CROWN_PLATFORM_POSIX
  263. FILE* file = popen(string_stream::c_str(path), "r");
  264. char buf[1024];
  265. while (fgets(buf, sizeof(buf), file) != NULL)
  266. output << buf;
  267. return pclose(file);
  268. #elif CROWN_PLATFORM_WINDOWS
  269. STARTUPINFO info;
  270. memset(&info, 0, sizeof(info));
  271. info.cb = sizeof(info);
  272. PROCESS_INFORMATION process;
  273. memset(&process, 0, sizeof(process));
  274. int err = CreateProcess(argv[0]
  275. , (LPSTR)string_stream::c_str(path)
  276. , NULL
  277. , NULL
  278. , FALSE
  279. , CREATE_NO_WINDOW
  280. , NULL
  281. , NULL
  282. , &info
  283. , &process
  284. );
  285. CE_ASSERT(err != 0, "CreateProcess: GetLastError = %d", GetLastError());
  286. CE_UNUSED(err);
  287. DWORD exitcode = 1;
  288. ::WaitForSingleObject(process.hProcess, INFINITE);
  289. GetExitCodeProcess(process.hProcess, &exitcode);
  290. CloseHandle(process.hProcess);
  291. CloseHandle(process.hThread);
  292. return (int)exitcode;
  293. #endif
  294. }
  295. } // namespace os
  296. } // namespace crown