Standard setup for writing C inspired by Casey Muratori, Ryan Fleury, Mr. 4th Programmer, and others in the handmade community.
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 

493 wiersze
14 KiB

  1. #define STB_SPRINTF_IMPLEMENTATION
  2. #include "core.h"
  3. #include "os.h"
  4. void *pushSize(Arena *arena, size_t bytes) {
  5. if (arena->capacity - arena->head >= bytes) {
  6. void *ptr = (char *)arena->memory + arena->head;
  7. arena->head += bytes;
  8. return ptr;
  9. }
  10. return 0;
  11. }
  12. Arena *arenaAlloc(size_t capacity) {
  13. Arena *result = (Arena *)os_alloc(sizeof(Arena) + capacity);
  14. result->memory = result + sizeof(Arena);
  15. result->capacity = capacity;
  16. result->head = 0;
  17. return result;
  18. }
  19. void arenaFree(Arena *arena) {
  20. os_free(arena);
  21. #if OS_WINDOWS
  22. VirtualFree(arena, NULL, MEM_RELEASE);
  23. #elif OS_LINUX
  24. // TODO(dledda): implement this for Linux
  25. Assert(false);
  26. #endif
  27. }
  28. void arenaFreeFrom(Arena *arena, size_t position) {
  29. arena->head = position;
  30. }
  31. Arena *scratchArenas[2];
  32. void initialiseCore() {
  33. for (EachInArray(scratchArenas, i)) {
  34. scratchArenas[i] = arenaAlloc(Megabytes(64));
  35. }
  36. }
  37. Scratch scratchStart(Arena **conflicts, size_t conflictCount) {
  38. Scratch scratch = {0};
  39. for (size_t i = 0; i < ArrayCount(scratchArenas); i += 1) {
  40. bool conflicted = false;
  41. for (Arena **conflict = conflicts; conflict < conflicts + conflictCount; conflict += 1) {
  42. if (*conflict == scratchArenas[i]) {
  43. conflicted = true;
  44. break;
  45. }
  46. }
  47. if (conflicted == false) {
  48. scratch.arena = scratchArenas[i];
  49. scratch.start = scratch.arena->head;
  50. break;
  51. }
  52. }
  53. return scratch;
  54. }
  55. void scratchEnd(Scratch scratch) {
  56. arenaFreeFrom(scratch.arena, scratch.start);
  57. }
  58. template <typename T>
  59. T *appendList(list<T> *list, T element) {
  60. if (list->head < list->length) {
  61. list->data[list->head] = element;
  62. list->head++;
  63. return &(list->data[list->head - 1]);
  64. } else {
  65. return 0;
  66. }
  67. }
  68. template <typename T>
  69. void zeroListFull(list<T> *list) {
  70. memset(list->data, 0, list->head * sizeof(T));
  71. }
  72. template <typename T>
  73. void zeroList(list<T> *list) {
  74. list->head = 0;
  75. memset(list->data, 0, list->head * sizeof(T));
  76. }
  77. const char *cstring(Arena *arena, list<char> buf) {
  78. char *arr = PushArray(arena, char, buf.length + 1);
  79. memmove(arr, buf.data, buf.length);
  80. arr[buf.length] = '\0';
  81. return arr;
  82. }
  83. const char *cstring(Arena *arena, string str) {
  84. char *arr = PushArray(arena, char, str.length + 1);
  85. memmove(arr, str.str, str.length);
  86. arr[str.length] = '\0';
  87. return arr;
  88. }
  89. bool strEql(string s1, string s2) {
  90. if (s1.length != s2.length) {
  91. return false;
  92. }
  93. for (size_t i = 0; i < s1.length; i++) {
  94. if (s1.str[i] != s2.str[i]) {
  95. return false;
  96. }
  97. }
  98. return true;
  99. }
  100. size_t calcStringLen(const char *str) {
  101. size_t size = 0;
  102. if (str == NULL) {
  103. return size;
  104. }
  105. while (str[size] != '\0') {
  106. size++;
  107. }
  108. return size;
  109. }
  110. string strFromCString(Arena *arena, const char *str) {
  111. string result = PushString(arena, calcStringLen(str));
  112. memcpy(result.str, str, result.length);
  113. return result;
  114. }
  115. string strReverse(Arena *arena, string str) {
  116. string reversed = PushString(arena, str.length);
  117. for (
  118. size_t mainIndex = str.length - 1, reversedIndex = 0;
  119. mainIndex < str.length;
  120. mainIndex--, reversedIndex++
  121. ) {
  122. reversed.str[reversedIndex] = str.str[mainIndex];
  123. }
  124. return reversed;
  125. }
  126. string strPrintfv(Arena *arena, const char *fmt, va_list args) {
  127. string result = {0};
  128. va_list argsCopy;
  129. va_copy(argsCopy, args);
  130. uint64 bufSize = stb_vsnprintf(0, 0, fmt, args) + 1;
  131. result.str = PushArray(arena, char, bufSize);
  132. result.length = bufSize - 1;
  133. stb_vsnprintf((char *)result.str, (int)bufSize, fmt, argsCopy);
  134. return result;
  135. }
  136. string strPrintf(Arena *arena, const char *fmt, ...) {
  137. string result = {0};
  138. va_list args;
  139. va_start(args, fmt);
  140. result = strPrintfv(arena, fmt, args);
  141. va_end(args);
  142. return result;
  143. }
  144. template <typename T>
  145. list<T> listSlice(list<T> l, size_t start, size_t stop) {
  146. if (stop == 0) {
  147. stop = l.head;
  148. }
  149. // TODO(dledda): maybe assert instead
  150. if (stop > l.head || start > stop) {
  151. return {0};
  152. }
  153. return {
  154. l.data + start,
  155. stop - start,
  156. stop - start,
  157. };
  158. }
  159. string strSlice(string str, size_t start, size_t stop) {
  160. if (stop == 0) {
  161. stop = str.length;
  162. }
  163. // TODO(dledda): maybe assert instead
  164. if (stop > str.length || start > stop) {
  165. return {0};
  166. }
  167. return {
  168. str.str + start,
  169. stop - start,
  170. };
  171. }
  172. string strSlice(char *data, size_t start, size_t stop) {
  173. return {
  174. data + start,
  175. stop - start,
  176. };
  177. }
  178. bool stringContains(string str, char c) {
  179. for (size_t i = 0; i < str.length; i++) {
  180. if (str.str[i] == c) {
  181. return true;
  182. }
  183. }
  184. return false;
  185. }
  186. const char NUMERIC_CHARS[] = "0123456789";
  187. inline bool isNumeric(char c) {
  188. return stringContains(strlit(NUMERIC_CHARS), c);
  189. }
  190. list<string> strSplit(Arena *arena, string splitStr, string inputStr) {
  191. list<string> result = {0};
  192. if (inputStr.length > 0) {
  193. size_t splitCount = 0;
  194. size_t c = 0;
  195. size_t start = 0;
  196. void *beginning = (char *)arena->memory + arena->head;
  197. while (c < inputStr.length - splitStr.length) {
  198. if (strEql(strSlice(inputStr, c, c + splitStr.length), splitStr)) {
  199. string *splitString = PushStruct(arena, string);
  200. splitString->str = inputStr.str + start;
  201. splitString->length = c - start;
  202. splitCount++;
  203. start = c + 1;
  204. }
  205. c++;
  206. }
  207. string *splitString = PushStruct(arena, string);
  208. splitString->str = inputStr.str + start;
  209. splitString->length = inputStr.length - start;
  210. splitCount++;
  211. result.data = (string *)beginning,
  212. result.head = splitCount,
  213. result.length = splitCount;
  214. }
  215. return result;
  216. }
  217. int8 parsePositiveInt(string str, size_t *lengthPointer) {
  218. size_t numEnd = 0;
  219. char currChar = str.str[numEnd];
  220. while (numEnd < str.length && isNumeric(currChar)) {
  221. currChar = str.str[++numEnd];
  222. *lengthPointer += 1;
  223. }
  224. *lengthPointer -= 1;
  225. if (numEnd > 0) {
  226. uint8 result = 0;
  227. for (size_t i = 0; i < numEnd; i++) {
  228. result *= 10;
  229. result += str.str[i] - '0';
  230. }
  231. return result;
  232. } else {
  233. return -1;
  234. }
  235. }
  236. real32 parsePositiveReal32(string str, size_t *lengthPointer) {
  237. real32 result = NAN;
  238. string wholePartStr = string{0};
  239. string fractionalPartStr = string{0};
  240. bool split = false;
  241. size_t c = 0;
  242. while (c < str.length) {
  243. if (str.str[c] == '.') {
  244. wholePartStr.str = str.str;
  245. wholePartStr.length = c;
  246. fractionalPartStr.str = str.str + c + 1;
  247. fractionalPartStr.length = str.length - c - 1;
  248. split = true;
  249. break;
  250. }
  251. c++;
  252. }
  253. if (split) {
  254. int wholePart = parsePositiveInt(wholePartStr, lengthPointer);
  255. *lengthPointer += 1;
  256. int fractionalPart = parsePositiveInt(fractionalPartStr, lengthPointer);
  257. if (wholePart >= 0 && fractionalPart >= 0) {
  258. real32 fractionalPartMultiplier = 1.0f / powf(10.0f, (real32)fractionalPartStr.length);
  259. result = (real32)wholePart + (real32)fractionalPart * (real32)fractionalPartMultiplier;
  260. }
  261. } else if (c > 0) {
  262. result = (real32)parsePositiveInt(str, lengthPointer);
  263. }
  264. return result;
  265. }
  266. string readEntireFile(Arena *arena, string filename) {
  267. #if OS_WINDOWS
  268. string result = {0};
  269. HANDLE fileHandle = CreateFileA(cstring(arena, filename), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
  270. if (fileHandle != INVALID_HANDLE_VALUE) {
  271. LARGE_INTEGER fileSize;
  272. if (GetFileSizeEx(fileHandle, &fileSize)) {
  273. string readfile = PushString(arena, (size_t)fileSize.QuadPart);
  274. if (readfile.str) {
  275. DWORD bytesRead;
  276. if (ReadFile(fileHandle, readfile.str, (DWORD)fileSize.QuadPart, &bytesRead, NULL) && (fileSize.QuadPart == bytesRead)) {
  277. result = readfile;
  278. }
  279. }
  280. }
  281. CloseHandle(fileHandle);
  282. }
  283. return result;
  284. #elif OS_LINUX
  285. FILE *input = fopen((char *)filename.str, "r");
  286. struct stat st;
  287. stat((char *)filename.str, &st);
  288. size_t fsize = st.st_size;
  289. string readBuffer = PushString(arena, filesize);
  290. readBuffer.length = filesize;
  291. fread(readBuffer.str, sizeof(byte), filesize, input);
  292. fclose(input);
  293. return readBuffer;
  294. #endif
  295. }
  296. bool writeEntireFile(Arena *arena, string filename, const byte *contents, size_t contentsLength) {
  297. #if OS_WINDOWS
  298. bool result = false;
  299. HANDLE fileHandle = CreateFileA(cstring(arena, filename), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL);
  300. if (fileHandle != INVALID_HANDLE_VALUE) {
  301. DWORD bytesWritten;
  302. if (WriteFile(fileHandle, contents, (DWORD)contentsLength, &bytesWritten, NULL)) {
  303. // file written successfully
  304. result = bytesWritten == contentsLength;
  305. }
  306. CloseHandle(fileHandle);
  307. }
  308. return result;
  309. #elif OS_LINUX
  310. Assert(false);
  311. #endif
  312. }
  313. bool fileAppend(Arena *arena, string filename, const byte *contents, size_t contentsLength) {
  314. #if OS_WINDOWS
  315. bool result = false;
  316. HANDLE fileHandle = CreateFileA(cstring(arena, filename), FILE_APPEND_DATA | FILE_GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  317. if (fileHandle != INVALID_HANDLE_VALUE) {
  318. DWORD bytesWritten;
  319. DWORD position = SetFilePointer(fileHandle, 0, NULL, FILE_END);
  320. if (WriteFile(fileHandle, contents, (DWORD)contentsLength, &bytesWritten, NULL)) {
  321. // file written successfully
  322. result = bytesWritten == contentsLength;
  323. }
  324. CloseHandle(fileHandle);
  325. }
  326. return result;
  327. #elif OS_LINUX
  328. Assert(false);
  329. #endif
  330. }
  331. list<string> getArgs(Arena *arena, int argc, char **argv) {
  332. list<string> args = PushList(arena, string, (size_t)argc);
  333. for (int i = 1; i < argc; i++) {
  334. appendList(&args, strFromCString(arena, argv[i]));
  335. }
  336. return args;
  337. }
  338. UnixTimestamp getSystemUnixTime() {
  339. time_t now;
  340. time(&now);
  341. return (UnixTimestamp)now;
  342. }
  343. Timestamp timestampFromUnixTime(UnixTimestamp *unixTimestamp) {
  344. tm *timestamp = gmtime((time_t *)&time);
  345. return *timestamp;
  346. }
  347. string formatTimeHms(Arena *arena, UnixTimestamp time) {
  348. local_persist const string format = strlit("HH-MM-SS");
  349. string buf = PushString(arena, format.length);
  350. tm *timestamp = gmtime((time_t *)&time);
  351. strftime(buf.str, buf.length + 1, "%T", timestamp);
  352. return buf;
  353. }
  354. string formatTimeHms(Arena *arena, Timestamp *time) {
  355. local_persist const string format = strlit("HH-MM-SS");
  356. string buf = PushString(arena, format.length);
  357. strftime(buf.str, buf.length + 1, "%T", (tm *)time);
  358. return buf;
  359. }
  360. string formatTimeYmd(Arena *arena, UnixTimestamp time) {
  361. local_persist const string format = strlit("YYYY-mm-dd");
  362. string buf = PushString(arena, format.length);
  363. tm *timestamp = gmtime((time_t *)&time);
  364. strftime(buf.str, buf.length + 1, "%Y-%m-%d", timestamp);
  365. return buf;
  366. }
  367. string formatTimeYmd(Arena *arena, Timestamp *time) {
  368. local_persist const string format = strlit("YYYY-mm-dd");
  369. string buf = PushString(arena, format.length);
  370. strftime(buf.str, buf.length + 1, "%Y-%m-%d", (tm *)time);
  371. return buf;
  372. }
  373. function void __core_log(LogTarget target, const char *fmt, va_list argList) {
  374. Scratch scratch = scratchStart(0, 0);
  375. string result = strPrintfv(scratch.arena, fmt, argList);
  376. #if OS_WINDOWS
  377. DWORD done;
  378. HANDLE stdHandle;
  379. switch (target) {
  380. case LogTarget_stdin:
  381. stdHandle = GetStdHandle(STD_INPUT_HANDLE);
  382. break;
  383. case LogTarget_stdout:
  384. stdHandle = GetStdHandle(STD_ERROR_HANDLE);
  385. break;
  386. case LogTarget_stderr:
  387. stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
  388. break;
  389. default:
  390. stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
  391. break;
  392. }
  393. WriteFile(stdHandle, result.str, (DWORD)result.length, &done, 0);
  394. #elif OS_LINUX
  395. // TODO(dledda): implementation
  396. Assert(false);
  397. #endif
  398. scratchEnd(scratch);
  399. }
  400. void logErr(const char *fmt, ...) {
  401. va_list argList;
  402. va_start(argList, fmt);
  403. __core_log(LogTarget_stdout, fmt, argList);
  404. va_end(argList);
  405. }
  406. function void logStdout(const char *fmt, ...) {
  407. va_list argList;
  408. va_start(argList, fmt);
  409. __core_log(LogTarget_stdout, fmt, argList);
  410. va_end(argList);
  411. }
  412. void log(const char *fmt, ...) {
  413. va_list argList;
  414. va_start(argList, fmt);
  415. __core_log(LogTarget_stdout, fmt, argList);
  416. va_end(argList);
  417. }
  418. void log(list<int> l, LogTarget target) {
  419. void (*logFn)(const char *fmt, ...) = target == LogTarget_stdout ? &logStdout : &logErr;
  420. logFn("{ ");
  421. for (size_t i = 0; i < l.length; i++) {
  422. if (i != 0) {
  423. logFn(", ");
  424. }
  425. logFn("%i", l.data[i]);
  426. }
  427. logFn(" } length: %zu, head: %zu\n", l.length, l.head);
  428. }
  429. void log(list<string> l, LogTarget target) {
  430. void (*logFn)(const char *fmt, ...) = target == LogTarget_stdout ? &logStdout : &logErr;
  431. logFn("{ ");
  432. for (size_t i = 0; i < l.length; i++) {
  433. if (i != 0) {
  434. logFn(", ");
  435. }
  436. logFn("\"%S\"", l.data[i]);
  437. }
  438. logFn(" } length: %zu, head: %zu\n", l.length, l.head);
  439. }
  440. int intCompare(const void *a, const void *b) {
  441. int *x = (int *)a;
  442. int *y = (int *)b;
  443. return (*x > *y) - (*x < *y);
  444. }