Standard setup for writing C inspired by Casey Muratori, Ryan Fleury, Mr. 4th Programmer, and others in the handmade community.
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 

462 satır
12 KiB

  1. #include "os.c"
  2. #include "math.h"
  3. #include "string.h" // for memmove
  4. #include "core.h"
  5. #define STB_SPRINTF_IMPLEMENTATION
  6. #include "vendor/stb_sprintf.h"
  7. void *pushSizeFill(Arena *arena, size_t bytes, byte fill) {
  8. if (arena->capacity - arena->head >= bytes) {
  9. void *ptr = (byte *)arena->memory + arena->head;
  10. arena->head += bytes;
  11. memset(ptr, fill, bytes);
  12. return ptr;
  13. }
  14. return 0;
  15. }
  16. void *pushSize(Arena *arena, size_t bytes) {
  17. if (arena->capacity - arena->head >= bytes) {
  18. void *ptr = (byte *)arena->memory + arena->head;
  19. arena->head += bytes;
  20. return ptr;
  21. }
  22. return 0;
  23. }
  24. Arena *arenaAlloc(size_t capacity) {
  25. Arena *result = (Arena *)os_alloc(sizeof(Arena) + capacity);
  26. result->memory = (byte *)result + sizeof(Arena);
  27. result->capacity = capacity;
  28. result->head = 0;
  29. return result;
  30. }
  31. void arenaFree(Arena *arena) {
  32. os_free(arena, arena->capacity);
  33. }
  34. void arenaFreeFrom(Arena *arena, size_t position) {
  35. arena->head = position;
  36. }
  37. void arenaPopTo(Arena *arena, void *position) {
  38. arena->head = (byte *)position - (byte *)arena->memory;
  39. }
  40. Arena *scratchArenas[2];
  41. void initialiseDjStdCore() {
  42. for (EachInArray(scratchArenas, i)) {
  43. scratchArenas[i] = arenaAlloc(Megabytes(64));
  44. }
  45. }
  46. Scratch scratchStart(Arena **conflicts, size_t conflictCount) {
  47. Scratch scratch = {0};
  48. for (size_t i = 0; i < ArrayCount(scratchArenas); i += 1) {
  49. bool conflicted = false;
  50. for (Arena **conflict = conflicts; conflict < conflicts + conflictCount; conflict += 1) {
  51. if (*conflict == scratchArenas[i]) {
  52. conflicted = true;
  53. break;
  54. }
  55. }
  56. if (conflicted == false) {
  57. scratch.arena = scratchArenas[i];
  58. scratch.start = scratch.arena->head;
  59. break;
  60. }
  61. }
  62. return scratch;
  63. }
  64. void scratchEnd(Scratch scratch) {
  65. arenaFreeFrom(scratch.arena, scratch.start);
  66. }
  67. const char *cstring(Arena *arena, string str) {
  68. char *arr = PushArray(arena, char, str.length + 1);
  69. memmove(arr, str.str, str.length);
  70. arr[str.length] = '\0';
  71. return arr;
  72. }
  73. const char *cstringFromCharList(Arena *arena, CharList buf) {
  74. char *arr = PushArray(arena, char, buf.length + 1);
  75. memmove(arr, buf.data, buf.length);
  76. arr[buf.length] = '\0';
  77. return arr;
  78. }
  79. bool strStartsWith(string str, string testStr) {
  80. if (str.length < testStr.length) {
  81. return false;
  82. }
  83. for (size_t i = 0; i < testStr.length; i++) {
  84. if (str.str[i] != testStr.str[i]) {
  85. return false;
  86. }
  87. }
  88. return true;
  89. }
  90. bool strEql(string s1, string s2) {
  91. if (s1.length != s2.length) {
  92. return false;
  93. }
  94. for (size_t i = 0; i < s1.length; i++) {
  95. if (s1.str[i] != s2.str[i]) {
  96. return false;
  97. }
  98. }
  99. return true;
  100. }
  101. size_t calcStringLen(const char *str) {
  102. size_t size = 0;
  103. if (str == NULL) {
  104. return size;
  105. }
  106. while (str[size] != '\0') {
  107. size++;
  108. }
  109. return size;
  110. }
  111. string strFromCString(Arena *arena, const char *str) {
  112. string result = PushString(arena, calcStringLen(str));
  113. memcpy(result.str, str, result.length);
  114. return result;
  115. }
  116. string strReverse(Arena *arena, string str) {
  117. string reversed = PushString(arena, str.length);
  118. for (
  119. size_t mainIndex = str.length - 1, reversedIndex = 0;
  120. mainIndex < str.length;
  121. mainIndex--, reversedIndex++
  122. ) {
  123. reversed.str[reversedIndex] = str.str[mainIndex];
  124. }
  125. return reversed;
  126. }
  127. string strPrintfv(Arena *arena, const char *fmt, va_list args) {
  128. string result = {0};
  129. va_list argsCopy;
  130. va_copy(argsCopy, args);
  131. uint64 bufSize = stb_vsnprintf(0, 0, fmt, args) + 1;
  132. result.str = PushArray(arena, char, bufSize);
  133. result.length = bufSize - 1;
  134. stb_vsnprintf((char *)result.str, (int)bufSize, fmt, argsCopy);
  135. return result;
  136. }
  137. string strPrintf(Arena *arena, const char *fmt, ...) {
  138. string result = {0};
  139. va_list args;
  140. va_start(args, fmt);
  141. result = strPrintfv(arena, fmt, args);
  142. va_end(args);
  143. return result;
  144. }
  145. string strSlice(string str, size_t start, size_t stop) {
  146. if (stop == 0) {
  147. stop = str.length;
  148. }
  149. // TODO(djledda): maybe assert instead
  150. if (stop > str.length || start > stop) {
  151. return (string){0};
  152. }
  153. return (string){
  154. str.str + start,
  155. stop - start,
  156. };
  157. }
  158. string strSliceCStr(char *data, size_t start, size_t stop) {
  159. return (string){
  160. data + start,
  161. stop - start,
  162. };
  163. }
  164. bool stringContains(string str, char c) {
  165. for (size_t i = 0; i < str.length; i++) {
  166. if (str.str[i] == c) {
  167. return true;
  168. }
  169. }
  170. return false;
  171. }
  172. string NUMERIC_CHARS = s("0123456789");
  173. inline bool isNumeric(char c) {
  174. return stringContains(NUMERIC_CHARS, c);
  175. }
  176. StringList strSplit(Arena *arena, string splitStr, string inputStr) {
  177. StringList result = {0};
  178. if (inputStr.length > 0) {
  179. size_t splitCount = 0;
  180. size_t c = 0;
  181. size_t start = 0;
  182. void *beginning = arena->memory + arena->head;
  183. while (c < inputStr.length) {
  184. string mystr = strSlice(inputStr, c, c + splitStr.length);
  185. if (strEql(mystr, splitStr)) {
  186. string *splitString = PushStruct(arena, string);
  187. splitString->str = inputStr.str + start;
  188. splitString->length = c - start;
  189. splitCount++;
  190. start = c + splitStr.length;
  191. }
  192. c++;
  193. }
  194. string *splitString = PushStruct(arena, string);
  195. splitString->str = inputStr.str + start;
  196. splitString->length = inputStr.length - start;
  197. splitCount++;
  198. result.data = (string *)beginning;
  199. result.length = splitCount;
  200. result.capacity = splitCount;
  201. }
  202. return result;
  203. }
  204. Int32Result parsePositiveInt(string str) {
  205. size_t numEnd = 0;
  206. char currChar = str.str[numEnd];
  207. while (numEnd < str.length && isNumeric(currChar)) {
  208. numEnd++;
  209. currChar = str.str[numEnd];
  210. }
  211. if (numEnd > 0) {
  212. uint32 result = 0;
  213. for (size_t i = 0; i < numEnd; i++) {
  214. result *= 10;
  215. result += str.str[i] - '0';
  216. }
  217. return (Int32Result){ .result=result, .valid=true };
  218. } else {
  219. return (Int32Result){ .result=0, .valid=false};
  220. }
  221. }
  222. Real32Result parsePositiveReal32(string str) {
  223. Real32Result result = { .result=NAN, .valid=false};
  224. string wholePartStr = (string){0};
  225. string fractionalPartStr = (string){0};
  226. bool split = false;
  227. size_t c = 0;
  228. while (c < str.length) {
  229. if (str.str[c] == '.') {
  230. wholePartStr.str = str.str;
  231. wholePartStr.length = c;
  232. fractionalPartStr.str = str.str + c + 1;
  233. fractionalPartStr.length = str.length - c - 1;
  234. split = true;
  235. break;
  236. }
  237. c++;
  238. }
  239. if (split) {
  240. Int32Result wholePartParsed = parsePositiveInt(wholePartStr);
  241. Int32Result fractionalPartParsed = parsePositiveInt(fractionalPartStr);
  242. if (wholePartParsed.valid && fractionalPartParsed.valid) {
  243. // TODO(dledda): implement powf with intrinsics? or just custom
  244. real32 fractionalPartMultiplier = 1.0f / powf(10.0f, (real32)fractionalPartStr.length);
  245. result.result = (real32)wholePartParsed.result + (real32)fractionalPartParsed.result * (real32)fractionalPartMultiplier;
  246. result.valid = true;
  247. }
  248. } else if (c > 0) {
  249. Int32Result intPartParsed = parsePositiveInt(str);
  250. if (intPartParsed.valid) {
  251. result.result = (real32)intPartParsed.result;
  252. result.valid = true;
  253. }
  254. }
  255. return result;
  256. }
  257. StringList getArgs(Arena *arena, int argc, char **argv) {
  258. StringList args = PushList(arena, StringList, (size_t)argc - 1);
  259. for (int i = 1; i < argc; i++) {
  260. AppendList(&args, strFromCString(arena, argv[i]));
  261. }
  262. return args;
  263. }
  264. UnixTimestamp getSystemUnixTime() {
  265. time_t now;
  266. time(&now);
  267. return (UnixTimestamp)now;
  268. }
  269. Timestamp timestampFromUnixTime(UnixTimestamp *unixTimestamp) {
  270. struct tm *timestamp = gmtime((time_t *)unixTimestamp);
  271. return *timestamp;
  272. }
  273. string formatTimeHmsUnix(Arena *arena, UnixTimestamp time) {
  274. local_persist const string format = s("HH-MM-SS");
  275. string buf = PushString(arena, format.length);
  276. struct tm *timestamp = gmtime((time_t *)&time);
  277. strftime(buf.str, buf.length + 1, "%T", timestamp);
  278. return buf;
  279. }
  280. string formatTimeHms(Arena *arena, Timestamp *time) {
  281. local_persist const string format = s("HH-MM-SS");
  282. string buf = PushString(arena, format.length);
  283. strftime(buf.str, buf.length + 1, "%T", (struct tm *)time);
  284. return buf;
  285. }
  286. string formatTimeYmdUnix(Arena *arena, UnixTimestamp time) {
  287. local_persist const string format = s("YYYY-mm-dd");
  288. string buf = PushString(arena, format.length);
  289. struct tm *timestamp = gmtime((time_t *)&time);
  290. strftime(buf.str, buf.length + 1, "%Y-%m-%d", timestamp);
  291. return buf;
  292. }
  293. string formatTimeYmd(Arena *arena, Timestamp *time) {
  294. local_persist const string format = s("YYYY-mm-dd");
  295. string buf = PushString(arena, format.length);
  296. strftime(buf.str, buf.length + 1, "%Y-%m-%d", (struct tm *)time);
  297. return buf;
  298. }
  299. function void printStderr(const char *fmt, ...) {
  300. va_list argList;
  301. va_start(argList, fmt);
  302. os_print(StdStream_stdout, fmt, argList);
  303. va_end(argList);
  304. }
  305. function void printlnStderr(const char *fmt, ...) {
  306. va_list argList;
  307. va_start(argList, fmt);
  308. os_println(StdStream_stdout, fmt, argList);
  309. va_end(argList);
  310. }
  311. function void printStdout(const char *fmt, ...) {
  312. va_list argList;
  313. va_start(argList, fmt);
  314. os_print(StdStream_stdout, fmt, argList);
  315. va_end(argList);
  316. }
  317. function void printlnStdout(const char *fmt, ...) {
  318. va_list argList;
  319. va_start(argList, fmt);
  320. os_println(StdStream_stdout, fmt, argList);
  321. va_end(argList);
  322. }
  323. void (*print)(const char *fmt, ...) = &printStdout;
  324. void (*println)(const char *fmt, ...) = &printlnStdout;
  325. void setStdout() {
  326. print = &printStdout;
  327. println = &printlnStdout;
  328. }
  329. void setStderr() {
  330. print = &printStderr;
  331. println = &printlnStderr;
  332. }
  333. #define UseStderr() DeferLoop(setStderr(), setStdout())
  334. // TODO(dledda): mat print functions
  335. /*
  336. void print(list<Vector4<real32>> l, StdStream target) {
  337. void (*logFn)(const char *fmt, ...) = target == StdStream_stdout ? &printStdout : &printStderr;
  338. logFn("{ ");
  339. for (size_t i = 0; i < l.length; i++) {
  340. if (i != 0) {
  341. logFn(", ");
  342. }
  343. logFn("{ %.2f, %.2f, %.2f, %.2f }", l.data[i].x, l.data[i].y, l.data[i].z, l.data[i].w);
  344. }
  345. logFn(" } length: %zu, head: %zu\n", l.length, l.head);
  346. }
  347. void print(list<Vector3<real32>> l, StdStream target) {
  348. void (*logFn)(const char *fmt, ...) = target == StdStream_stdout ? &printStdout : &printStderr;
  349. logFn("{ ");
  350. for (size_t i = 0; i < l.length; i++) {
  351. if (i != 0) {
  352. logFn(", ");
  353. }
  354. logFn("{ %.2f, %.2f, %.2f }", l.data[i].x, l.data[i].y, l.data[i].z);
  355. }
  356. logFn(" } length: %zu, head: %zu\n", l.length, l.head);
  357. }
  358. void print(list<Vector2<real32>> l, StdStream target) {
  359. void (*logFn)(const char *fmt, ...) = target == StdStream_stdout ? &printStdout : &printStderr;
  360. logFn("{ ");
  361. for (size_t i = 0; i < l.length; i++) {
  362. if (i != 0) {
  363. logFn(", ");
  364. }
  365. logFn("{ %.2f, %.2f }", l.data[i].x, l.data[i].y);
  366. }
  367. logFn(" } length: %zu, head: %zu\n", l.length, l.head);
  368. }
  369. */
  370. void printIntList(IntList l) {
  371. print("{ ");
  372. for (size_t i = 0; i < l.length; i++) {
  373. if (i != 0) {
  374. print(", ");
  375. }
  376. print("%i", l.data[i]);
  377. }
  378. print(" } length: %zu, capacity: %zu\n", l.length, l.capacity);
  379. }
  380. void printStrList(StringList l) {
  381. print("{ ");
  382. for (size_t i = 0; i < l.length; i++) {
  383. if (i != 0) {
  384. print(", ");
  385. }
  386. print("\"%S\"", l.data[i]);
  387. }
  388. print(" } length: %zu, capacity: %zu\n", l.length, l.capacity);
  389. }
  390. int intCompare(const void *a, const void *b) {
  391. int *x = (int *)a;
  392. int *y = (int *)b;
  393. return (*x > *y) - (*x < *y);
  394. }
  395. #ifdef DJSTD_BASIC_ENTRY
  396. int djstd_entry(Arena* arena, StringList args);
  397. #ifndef DJSTD_BASIC_ENTRY_ARENA_ALLOC
  398. #define DJSTD_BASIC_ENTRY_ARENA_ALLOC Megabytes(64)
  399. #endif
  400. int main(int argc, char **argv) {
  401. initialiseDjStdCore();
  402. Arena *arena = arenaAlloc(DJSTD_BASIC_ENTRY_ARENA_ALLOC);
  403. StringList args = getArgs(arena, argc, argv);
  404. return djstd_entry(arena, args);
  405. }
  406. #endif