gravity_utils.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. //
  2. // gravity_utils.c
  3. // gravity
  4. //
  5. // Created by Marco Bambini on 29/08/14.
  6. // Copyright (c) 2014 CreoLabs. All rights reserved.
  7. //
  8. #include <time.h>
  9. #include <fcntl.h>
  10. #include <ctype.h>
  11. #include <string.h>
  12. #include <assert.h>
  13. #include <unistd.h>
  14. #include <sys/stat.h>
  15. #if defined(__linux)
  16. #include <sys/time.h>
  17. #endif
  18. #if defined(__MACH__)
  19. #include <mach/mach_time.h>
  20. #endif
  21. #if defined(_WIN32)
  22. #include <windows.h>
  23. #include <Shlwapi.h>
  24. #include <tchar.h>
  25. #endif
  26. #include "gravity_utils.h"
  27. #include "gravity_memory.h"
  28. #define SWP(x,y) (x^=y, y^=x, x^=y)
  29. // MARK: Timer -
  30. nanotime_t nanotime (void) {
  31. nanotime_t value;
  32. #if defined(_WIN32)
  33. static LARGE_INTEGER win_frequency;
  34. QueryPerformanceFrequency(&win_frequency);
  35. LARGE_INTEGER t;
  36. if (!QueryPerformanceCounter(&t)) return 0;
  37. value = (t.QuadPart / win_frequency.QuadPart) * 1000000000;
  38. value += (t.QuadPart % win_frequency.QuadPart) * 1000000000 / win_frequency.QuadPart;
  39. #elif defined(__MACH__)
  40. mach_timebase_info_data_t info;
  41. kern_return_t r;
  42. nanotime_t t;
  43. t = mach_absolute_time();
  44. r = mach_timebase_info(&info);
  45. if (r != 0) return 0;
  46. value = (t / info.denom) * info.numer;
  47. value += (t % info.denom) * info.numer / info.denom;
  48. #elif defined(__linux)
  49. struct timespec ts;
  50. int r;
  51. r = clock_gettime(CLOCK_MONOTONIC, &ts);
  52. if (r != 0) return 0;
  53. value = ts.tv_sec * (nanotime_t)1000000000 + ts.tv_nsec;
  54. #else
  55. struct timeval tv;
  56. int r;
  57. r = gettimeofday(&tv, 0);
  58. if (r != 0) return 0;
  59. value = tv.tv_sec * (nanotime_t)1000000000 + tv.tv_usec * 1000;
  60. #endif
  61. return value;
  62. }
  63. double microtime (nanotime_t tstart, nanotime_t tend) {
  64. nanotime_t t = tend - tstart;
  65. return ((double)t / 1000.0f);
  66. }
  67. double millitime (nanotime_t tstart, nanotime_t tend) {
  68. nanotime_t t = tend - tstart;
  69. return ((double)t / 1000000.0f);
  70. }
  71. // MARK: - I/O Functions -
  72. uint64_t file_size (const char *path) {
  73. #ifdef WIN32
  74. WIN32_FILE_ATTRIBUTE_DATA fileInfo;
  75. if (GetFileAttributesExA(path, GetFileExInfoStandard, (void*)&fileInfo) == 0) return -1;
  76. return (uint64_t)(((__int64)fileInfo.nFileSizeHigh) << 32 ) + fileInfo.nFileSizeLow;
  77. #else
  78. struct stat sb;
  79. if (stat(path, &sb) > 0) return -1;
  80. return (uint64_t)sb.st_size;
  81. #endif
  82. }
  83. const char *file_read(const char *path, size_t *len) {
  84. int fd = 0;
  85. off_t fsize = 0;
  86. size_t fsize2 = 0;
  87. char *buffer = NULL;
  88. fsize = (size_t) file_size(path);
  89. if (fsize < 0) goto abort_read;
  90. fd = open(path, O_RDONLY);
  91. if (fd < 0) goto abort_read;
  92. buffer = (char *)mem_alloc((size_t)fsize + 1);
  93. if (buffer == NULL) goto abort_read;
  94. buffer[fsize] = 0;
  95. fsize2 = read(fd, buffer, fsize);
  96. if (fsize2 == -1) goto abort_read;
  97. if (len) *len = fsize2;
  98. close(fd);
  99. return (const char *)buffer;
  100. abort_read:
  101. if (buffer) mem_free((void *)buffer);
  102. if (fd >= 0) close(fd);
  103. return NULL;
  104. }
  105. bool file_exists (const char *path) {
  106. #ifdef WIN32
  107. BOOL isDirectory;
  108. DWORD attributes = GetFileAttributesA(path);
  109. // special directory case to drive the network path check
  110. if (attributes == INVALID_FILE_ATTRIBUTES)
  111. isDirectory = (GetLastError() == ERROR_BAD_NETPATH);
  112. else
  113. isDirectory = (FILE_ATTRIBUTE_DIRECTORY & attributes);
  114. if (isDirectory) {
  115. if (PathIsNetworkPathA(path)) return true;
  116. if (PathIsUNCA(path)) return true;
  117. }
  118. if (PathFileExistsA(path) == 1) return true;
  119. #else
  120. if (access(path, F_OK)==0) return true;
  121. #endif
  122. return false;
  123. }
  124. const char *file_buildpath (const char *filename, const char *dirpath) {
  125. // #ifdef WIN32
  126. // PathCombineA(result, filename, dirpath);
  127. // #else
  128. size_t len1 = strlen(filename);
  129. size_t len2 = strlen(dirpath);
  130. size_t len = len1+len2+2;
  131. char *full_path = (char *)mem_alloc(len);
  132. if (!full_path) return NULL;
  133. if ((len2) && (dirpath[len2-1] != '/'))
  134. snprintf(full_path, len, "%s/%s", dirpath, filename);
  135. else
  136. snprintf(full_path, len, "%s%s", dirpath, filename);
  137. // #endif
  138. return (const char *)full_path;
  139. }
  140. bool file_write (const char *path, const char *buffer, size_t len) {
  141. // RW for owner, R for group, R for others
  142. #ifdef _WIN32
  143. mode_t mode = _S_IWRITE;
  144. #else
  145. mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
  146. #endif
  147. int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
  148. if (fd < 0) return false;
  149. ssize_t nwrite = write(fd, buffer, len);
  150. close(fd);
  151. return (nwrite == len);
  152. }
  153. // MARK: - Directory Functions -
  154. bool is_directory (const char *path) {
  155. #ifdef WIN32
  156. DWORD dwAttrs;
  157. dwAttrs = GetFileAttributesA(path);
  158. if (dwAttrs == INVALID_FILE_ATTRIBUTES) return false;
  159. if (dwAttrs & FILE_ATTRIBUTE_DIRECTORY) return true;
  160. #else
  161. struct stat buf;
  162. if (lstat(path, &buf) < 0) return false;
  163. if (S_ISDIR(buf.st_mode)) return true;
  164. #endif
  165. return false;
  166. }
  167. DIRREF directory_init (const char *dirpath) {
  168. #ifdef WIN32
  169. WIN32_FIND_DATA findData;
  170. WCHAR path[MAX_PATH];
  171. WCHAR dirpathW[MAX_PATH];
  172. HANDLE hFind;
  173. // convert dirpath to dirpathW
  174. MultiByteToWideChar(CP_UTF8, 0, dirpath, -1, dirpathW, MAX_PATH);
  175. // in this way I can be sure that the first file returned (and lost) is .
  176. PathCombineW(path, dirpathW, _T("*"));
  177. // if the path points to a symbolic link, the WIN32_FIND_DATA buffer contains
  178. // information about the symbolic link, not the target
  179. return FindFirstFileW(path, &findData);
  180. #else
  181. return opendir(dirpath);
  182. #endif
  183. }
  184. const char *directory_read (DIRREF ref) {
  185. if (ref == NULL) return NULL;
  186. while (1) {
  187. #ifdef WIN32
  188. WIN32_FIND_DATA findData;
  189. const char *file_name;
  190. if (FindNextFile(ref, &findData) == 0) {
  191. FindClose(ref);
  192. return NULL;
  193. }
  194. if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
  195. if (findData.cFileName == NULL) continue;
  196. if (findData.cFileName[0] == '.') continue;
  197. file_name = malloc(MAX_PATH);
  198. strncpy(file_name, findData.cFileName, MAX_PATH);
  199. return (const char *)file_name;
  200. #else
  201. struct dirent *d;
  202. if ((d = readdir(ref)) == NULL) {
  203. closedir(ref);
  204. return NULL;
  205. }
  206. if (d->d_name[0] == 0) continue;
  207. if (d->d_name[0] == '.') continue;
  208. return (const char *)d->d_name;
  209. #endif
  210. }
  211. return NULL;
  212. }
  213. // MARK: - String Functions -
  214. int string_nocasencmp(const char *s1, const char *s2, size_t n) {
  215. while(n > 0 && tolower((unsigned char)*s1) == tolower((unsigned char)*s2)) {
  216. if(*s1 == '\0') return 0;
  217. s1++;
  218. s2++;
  219. n--;
  220. }
  221. if(n == 0) return 0;
  222. return tolower((unsigned char)*s1) - tolower((unsigned char)*s2);
  223. }
  224. int string_casencmp(const char *s1, const char *s2, size_t n) {
  225. while(n > 0 && ((unsigned char)*s1) == ((unsigned char)*s2)) {
  226. if(*s1 == '\0') return 0;
  227. s1++;
  228. s2++;
  229. n--;
  230. }
  231. if(n == 0) return 0;
  232. return ((unsigned char)*s1) - ((unsigned char)*s2);
  233. }
  234. int string_cmp (const char *s1, const char *s2) {
  235. if (!s1) return 1;
  236. return strcmp(s1, s2);
  237. }
  238. const char *string_dup (const char *s1) {
  239. size_t len = (size_t)strlen(s1);
  240. char *s = (char *)mem_alloc(len + 1);
  241. memcpy(s, s1, len);
  242. return s;
  243. }
  244. const char *string_ndup (const char *s1, size_t n) {
  245. char *s = (char *)mem_alloc(n + 1);
  246. memcpy(s, s1, n);
  247. return s;
  248. }
  249. char *string_unescape (const char *s1, uint32_t *s1len, char *buffer) {
  250. uint32_t len = *s1len;
  251. uint32_t orig_len = len;
  252. for (uint32_t i=0, j=0; i<orig_len; ++i, ++j) {
  253. char c = s1[i];
  254. if ((c == '\\') && (i+1<orig_len)) {
  255. c = s1[i+1];
  256. switch (c) {
  257. case '"':
  258. case '\\':
  259. case '\b':
  260. case '\f':
  261. case '\n':
  262. case '\r':
  263. case '\t':
  264. ++i; --len; break;
  265. default:
  266. c = s1[i]; break;
  267. }
  268. }
  269. buffer[j] = c;
  270. }
  271. *s1len = len;
  272. return buffer;
  273. }
  274. // From: http://stackoverflow.com/questions/198199/how-do-you-reverse-a-string-in-place-in-c-or-c
  275. void string_reverse (char *p) {
  276. char *q = p;
  277. while(q && *q) ++q; /* find eos */
  278. for(--q; p < q; ++p, --q) SWP(*p, *q);
  279. }
  280. uint32_t string_size (const char *p) {
  281. if (!p) return 0;
  282. return (uint32_t)strlen(p);
  283. }
  284. // MARK: - UTF-8 Functions -
  285. /*
  286. Based on: https://github.com/Stepets/utf8.lua/blob/master/utf8.lua
  287. ABNF from RFC 3629
  288. UTF8-octets = *( UTF8-char )
  289. UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
  290. UTF8-1 = %x00-7F
  291. UTF8-2 = %xC2-DF UTF8-tail
  292. UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
  293. %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
  294. UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
  295. %xF4 %x80-8F 2( UTF8-tail )
  296. UTF8-tail = %x80-BF
  297. */
  298. inline uint32_t utf8_charbytes (const char *s, uint32_t i) {
  299. unsigned char c = s[i];
  300. // determine bytes needed for character, based on RFC 3629
  301. if ((c > 0) && (c <= 127)) return 1;
  302. if ((c >= 194) && (c <= 223)) return 2;
  303. if ((c >= 224) && (c <= 239)) return 3;
  304. if ((c >= 240) && (c <= 244)) return 4;
  305. // means error
  306. return 0;
  307. }
  308. uint32_t utf8_len (const char *s, uint32_t nbytes) {
  309. if (nbytes == 0) nbytes = (uint32_t)strlen(s);
  310. uint32_t pos = 1;
  311. uint32_t len = 0;
  312. while (pos <= nbytes) {
  313. ++len;
  314. uint32_t n = utf8_charbytes(s, pos);
  315. if (n == 0) return 0; // means error
  316. pos += n;
  317. }
  318. return len;
  319. }
  320. // From: http://stackoverflow.com/questions/198199/how-do-you-reverse-a-string-in-place-in-c-or-c
  321. void utf8_reverse (char *p) {
  322. char *q = p;
  323. string_reverse(p);
  324. // now fix bass-ackwards UTF chars.
  325. while(q && *q) ++q; // find eos
  326. while(p < --q)
  327. switch( (*q & 0xF0) >> 4 ) {
  328. case 0xF: /* U+010000-U+10FFFF: four bytes. */
  329. SWP(*(q-0), *(q-3));
  330. SWP(*(q-1), *(q-2));
  331. q -= 3;
  332. break;
  333. case 0xE: /* U+000800-U+00FFFF: three bytes. */
  334. SWP(*(q-0), *(q-2));
  335. q -= 2;
  336. break;
  337. case 0xC: /* fall-through */
  338. case 0xD: /* U+000080-U+0007FF: two bytes. */
  339. SWP(*(q-0), *(q-1));
  340. q--;
  341. break;
  342. }
  343. }
  344. // MARK: - Math -
  345. // From: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2Float
  346. uint32_t power_of2_ceil (uint32_t n) {
  347. n--;
  348. n |= n >> 1;
  349. n |= n >> 2;
  350. n |= n >> 4;
  351. n |= n >> 8;
  352. n |= n >> 16;
  353. n++;
  354. return n;
  355. }
  356. int64_t number_from_hex (const char *s, uint32_t len) {
  357. #pragma unused(len)
  358. return (int64_t) strtoll(s, NULL, 16);
  359. }
  360. int64_t number_from_oct (const char *s, uint32_t len) {
  361. #pragma unused(len)
  362. return (int64_t) strtoll(s, NULL, 8);
  363. }
  364. int64_t number_from_bin (const char *s, uint32_t len) {
  365. int64_t value = 0;
  366. for (uint32_t i=0; i<len; ++i) {
  367. int c = s[i];
  368. value = (value << 1) + (c - '0');
  369. }
  370. return value;
  371. }