gravity_utils.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  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: - Console Functions -
  72. #ifdef WIN32
  73. // getline is a POSIX function not available in C on Windows (only C++)
  74. static ssize_t getline (char **lineptr, size_t *n, FILE *stream) {
  75. // to be implemented on Windows
  76. // Never use gets: it offers no protections against a buffer overflow vulnerability.
  77. // see http://stackoverflow.com/questions/3302255/c-scanf-vs-gets-vs-fgets
  78. // we should implement something like ggets here
  79. // http://web.archive.org/web/20080525133110/http://cbfalconer.home.att.net/download/
  80. return -1;
  81. }
  82. #endif
  83. char *readline (char *prompt, int *length) {
  84. char *line = NULL;
  85. size_t size = 0;
  86. printf("%s", prompt);
  87. fflush(stdout);
  88. ssize_t nread = getline(&line, &size, stdin);
  89. if (nread == -1 || feof(stdin)) return NULL;
  90. *length = (int)nread;
  91. return line;
  92. }
  93. // MARK: - I/O Functions -
  94. uint64_t file_size (const char *path) {
  95. #ifdef WIN32
  96. WIN32_FILE_ATTRIBUTE_DATA fileInfo;
  97. if (GetFileAttributesExA(path, GetFileExInfoStandard, (void*)&fileInfo) == 0) return -1;
  98. return (uint64_t)(((__int64)fileInfo.nFileSizeHigh) << 32 ) + fileInfo.nFileSizeLow;
  99. #else
  100. struct stat sb;
  101. if (stat(path, &sb) > 0) return -1;
  102. return (uint64_t)sb.st_size;
  103. #endif
  104. }
  105. const char *file_read(const char *path, size_t *len) {
  106. int fd = 0;
  107. off_t fsize = 0;
  108. size_t fsize2 = 0;
  109. char *buffer = NULL;
  110. fsize = (size_t) file_size(path);
  111. if (fsize < 0) goto abort_read;
  112. fd = open(path, O_RDONLY);
  113. if (fd < 0) goto abort_read;
  114. buffer = (char *)mem_alloc((size_t)fsize + 1);
  115. if (buffer == NULL) goto abort_read;
  116. buffer[fsize] = 0;
  117. fsize2 = read(fd, buffer, fsize);
  118. if (fsize2 == -1) goto abort_read;
  119. if (len) *len = fsize2;
  120. close(fd);
  121. return (const char *)buffer;
  122. abort_read:
  123. if (buffer) mem_free((void *)buffer);
  124. if (fd >= 0) close(fd);
  125. return NULL;
  126. }
  127. bool file_exists (const char *path) {
  128. #ifdef WIN32
  129. BOOL isDirectory;
  130. DWORD attributes = GetFileAttributesA(path);
  131. // special directory case to drive the network path check
  132. if (attributes == INVALID_FILE_ATTRIBUTES)
  133. isDirectory = (GetLastError() == ERROR_BAD_NETPATH);
  134. else
  135. isDirectory = (FILE_ATTRIBUTE_DIRECTORY & attributes);
  136. if (isDirectory) {
  137. if (PathIsNetworkPathA(path)) return true;
  138. if (PathIsUNCA(path)) return true;
  139. }
  140. if (PathFileExistsA(path) == 1) return true;
  141. #else
  142. if (access(path, F_OK)==0) return true;
  143. #endif
  144. return false;
  145. }
  146. const char *file_buildpath (const char *filename, const char *dirpath) {
  147. // #ifdef WIN32
  148. // PathCombineA(result, filename, dirpath);
  149. // #else
  150. size_t len1 = strlen(filename);
  151. size_t len2 = strlen(dirpath);
  152. size_t len = len1+len2+2;
  153. char *full_path = (char *)mem_alloc(len);
  154. if (!full_path) return NULL;
  155. if ((len2) && (dirpath[len2-1] != '/'))
  156. snprintf(full_path, len, "%s/%s", dirpath, filename);
  157. else
  158. snprintf(full_path, len, "%s%s", dirpath, filename);
  159. // #endif
  160. return (const char *)full_path;
  161. }
  162. bool file_write (const char *path, const char *buffer, size_t len) {
  163. // RW for owner, R for group, R for others
  164. #ifdef _WIN32
  165. mode_t mode = _S_IWRITE;
  166. #else
  167. mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
  168. #endif
  169. int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
  170. if (fd < 0) return false;
  171. ssize_t nwrite = write(fd, buffer, len);
  172. close(fd);
  173. return (nwrite == len);
  174. }
  175. // MARK: - Directory Functions -
  176. bool is_directory (const char *path) {
  177. #ifdef WIN32
  178. DWORD dwAttrs;
  179. dwAttrs = GetFileAttributesA(path);
  180. if (dwAttrs == INVALID_FILE_ATTRIBUTES) return false;
  181. if (dwAttrs & FILE_ATTRIBUTE_DIRECTORY) return true;
  182. #else
  183. struct stat buf;
  184. if (lstat(path, &buf) < 0) return false;
  185. if (S_ISDIR(buf.st_mode)) return true;
  186. #endif
  187. return false;
  188. }
  189. DIRREF directory_init (const char *dirpath) {
  190. #ifdef WIN32
  191. WIN32_FIND_DATA findData;
  192. WCHAR path[MAX_PATH];
  193. WCHAR dirpathW[MAX_PATH];
  194. HANDLE hFind;
  195. (void)hFind;
  196. // convert dirpath to dirpathW
  197. MultiByteToWideChar(CP_UTF8, 0, dirpath, -1, dirpathW, MAX_PATH);
  198. // in this way I can be sure that the first file returned (and lost) is .
  199. PathCombineW(path, dirpathW, _T("*"));
  200. // if the path points to a symbolic link, the WIN32_FIND_DATA buffer contains
  201. // information about the symbolic link, not the target
  202. return FindFirstFileW(path, &findData);
  203. #else
  204. return opendir(dirpath);
  205. #endif
  206. }
  207. const char *directory_read (DIRREF ref) {
  208. if (ref == NULL) return NULL;
  209. while (1) {
  210. #ifdef WIN32
  211. WIN32_FIND_DATA findData;
  212. char *file_name;
  213. if (FindNextFile(ref, &findData) == 0) {
  214. FindClose(ref);
  215. return NULL;
  216. }
  217. if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
  218. if (findData.cFileName == NULL) continue;
  219. if (findData.cFileName[0] == '.') continue;
  220. return (const char*)findData.cFileName;
  221. #else
  222. struct dirent *d;
  223. if ((d = readdir(ref)) == NULL) {
  224. closedir(ref);
  225. return NULL;
  226. }
  227. if (d->d_name[0] == 0) continue;
  228. if (d->d_name[0] == '.') continue;
  229. return (const char *)d->d_name;
  230. #endif
  231. }
  232. return NULL;
  233. }
  234. // MARK: - String Functions -
  235. int string_nocasencmp(const char *s1, const char *s2, size_t n) {
  236. while(n > 0 && tolower((unsigned char)*s1) == tolower((unsigned char)*s2)) {
  237. if(*s1 == '\0') return 0;
  238. s1++;
  239. s2++;
  240. n--;
  241. }
  242. if(n == 0) return 0;
  243. return tolower((unsigned char)*s1) - tolower((unsigned char)*s2);
  244. }
  245. int string_casencmp(const char *s1, const char *s2, size_t n) {
  246. while(n > 0 && ((unsigned char)*s1) == ((unsigned char)*s2)) {
  247. if(*s1 == '\0') return 0;
  248. s1++;
  249. s2++;
  250. n--;
  251. }
  252. if(n == 0) return 0;
  253. return ((unsigned char)*s1) - ((unsigned char)*s2);
  254. }
  255. int string_cmp (const char *s1, const char *s2) {
  256. if (!s1) return 1;
  257. return strcmp(s1, s2);
  258. }
  259. const char *string_dup (const char *s1) {
  260. size_t len = (size_t)strlen(s1);
  261. char *s = (char *)mem_alloc(len + 1);
  262. memcpy(s, s1, len);
  263. return s;
  264. }
  265. const char *string_ndup (const char *s1, size_t n) {
  266. char *s = (char *)mem_alloc(n + 1);
  267. memcpy(s, s1, n);
  268. return s;
  269. }
  270. // From: http://stackoverflow.com/questions/198199/how-do-you-reverse-a-string-in-place-in-c-or-c
  271. void string_reverse (char *p) {
  272. char *q = p;
  273. while(q && *q) ++q; /* find eos */
  274. for(--q; p < q; ++p, --q) SWP(*p, *q);
  275. }
  276. uint32_t string_size (const char *p) {
  277. if (!p) return 0;
  278. return (uint32_t)strlen(p);
  279. }
  280. // MARK: - UTF-8 Functions -
  281. /*
  282. Based on: https://github.com/Stepets/utf8.lua/blob/master/utf8.lua
  283. ABNF from RFC 3629
  284. UTF8-octets = *( UTF8-char )
  285. UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
  286. UTF8-1 = %x00-7F
  287. UTF8-2 = %xC2-DF UTF8-tail
  288. UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
  289. %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
  290. UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
  291. %xF4 %x80-8F 2( UTF8-tail )
  292. UTF8-tail = %x80-BF
  293. */
  294. inline uint32_t utf8_charbytes (const char *s, uint32_t i) {
  295. unsigned char c = s[i];
  296. // determine bytes needed for character, based on RFC 3629
  297. if ((c > 0) && (c <= 127)) return 1;
  298. if ((c >= 194) && (c <= 223)) return 2;
  299. if ((c >= 224) && (c <= 239)) return 3;
  300. if ((c >= 240) && (c <= 244)) return 4;
  301. // means error
  302. return 0;
  303. }
  304. uint32_t utf8_nbytes (uint32_t n) {
  305. if (n <= 0x7f) return 1; // 127
  306. if (n <= 0x7ff) return 2; // 2047
  307. if (n <= 0xffff) return 3; // 65535
  308. if (n <= 0x10ffff) return 4; // 1114111
  309. return 0;
  310. }
  311. // from: https://github.com/munificent/wren/blob/master/src/vm/wren_utils.c
  312. uint32_t utf8_encode(char *buffer, uint32_t value) {
  313. char *bytes = buffer;
  314. if (value <= 0x7f) {
  315. // single byte (i.e. fits in ASCII).
  316. *bytes = value & 0x7f;
  317. return 1;
  318. }
  319. if (value <= 0x7ff) {
  320. // two byte sequence: 110xxxxx 10xxxxxx.
  321. *bytes = 0xc0 | ((value & 0x7c0) >> 6);
  322. ++bytes;
  323. *bytes = 0x80 | (value & 0x3f);
  324. return 2;
  325. }
  326. if (value <= 0xffff) {
  327. // three byte sequence: 1110xxxx 10xxxxxx 10xxxxxx.
  328. *bytes = 0xe0 | ((value & 0xf000) >> 12);
  329. ++bytes;
  330. *bytes = 0x80 | ((value & 0xfc0) >> 6);
  331. ++bytes;
  332. *bytes = 0x80 | (value & 0x3f);
  333. return 3;
  334. }
  335. if (value <= 0x10ffff) {
  336. // four byte sequence: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx.
  337. *bytes = 0xf0 | ((value & 0x1c0000) >> 18);
  338. ++bytes;
  339. *bytes = 0x80 | ((value & 0x3f000) >> 12);
  340. ++bytes;
  341. *bytes = 0x80 | ((value & 0xfc0) >> 6);
  342. ++bytes;
  343. *bytes = 0x80 | (value & 0x3f);
  344. return 4;
  345. }
  346. return 0;
  347. }
  348. uint32_t utf8_len (const char *s, uint32_t nbytes) {
  349. if (nbytes == 0) nbytes = (uint32_t)strlen(s);
  350. uint32_t pos = 1;
  351. uint32_t len = 0;
  352. while (pos <= nbytes) {
  353. ++len;
  354. uint32_t n = utf8_charbytes(s, pos);
  355. if (n == 0) return 0; // means error
  356. pos += n;
  357. }
  358. return len;
  359. }
  360. // From: http://stackoverflow.com/questions/198199/how-do-you-reverse-a-string-in-place-in-c-or-c
  361. bool utf8_reverse (char *p) {
  362. char *q = p;
  363. string_reverse(p);
  364. // now fix bass-ackwards UTF chars.
  365. while(q && *q) ++q; // find eos
  366. while(p < --q)
  367. switch( (*q & 0xF0) >> 4 ) {
  368. case 0xF: /* U+010000-U+10FFFF: four bytes. */
  369. if (q-p < 4) return false;
  370. SWP(*(q-0), *(q-3));
  371. SWP(*(q-1), *(q-2));
  372. q -= 3;
  373. break;
  374. case 0xE: /* U+000800-U+00FFFF: three bytes. */
  375. if (q-p < 3) return false;
  376. SWP(*(q-0), *(q-2));
  377. q -= 2;
  378. break;
  379. case 0xC: /* fall-through */
  380. case 0xD: /* U+000080-U+0007FF: two bytes. */
  381. if (q-p < 1) return false;
  382. SWP(*(q-0), *(q-1));
  383. q--;
  384. break;
  385. }
  386. return true;
  387. }
  388. // MARK: - Math -
  389. // From: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2Float
  390. uint32_t power_of2_ceil (uint32_t n) {
  391. n--;
  392. n |= n >> 1;
  393. n |= n >> 2;
  394. n |= n >> 4;
  395. n |= n >> 8;
  396. n |= n >> 16;
  397. n++;
  398. return n;
  399. }
  400. int64_t number_from_hex (const char *s, uint32_t len) {
  401. #pragma unused(len)
  402. return (int64_t) strtoll(s, NULL, 16);
  403. }
  404. int64_t number_from_oct (const char *s, uint32_t len) {
  405. #pragma unused(len)
  406. return (int64_t) strtoll(s, NULL, 8);
  407. }
  408. int64_t number_from_bin (const char *s, uint32_t len) {
  409. int64_t value = 0;
  410. for (uint32_t i=0; i<len; ++i) {
  411. int c = s[i];
  412. value = (value << 1) + (c - '0');
  413. }
  414. return value;
  415. }