Standard setup for writing C inspired by Casey Muratori, Ryan Fleury, Mr. 4th Programmer, and others in the handmade community.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

462 linhas
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