Compare commits
10 Commits
3f21a6722e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7660402d08 | ||
|
|
18100a87fb | ||
|
|
da575e8877 | ||
|
|
1a1432592a | ||
|
|
71d36352cb | ||
|
|
1b48585308 | ||
|
|
0c4d19c9b8 | ||
|
|
6c4c141344 | ||
|
|
c944ceac4b | ||
|
|
bc12273f2a |
@@ -3,6 +3,4 @@ mkdir build
|
||||
cd build
|
||||
cl -Fe:bld.exe ../build_tool/main.cpp -FC -WX -W3 -wd4200 -diagnostics:column -nologo -Zi -D_CRT_SECURE_NO_WARNINGS
|
||||
cd ..
|
||||
rem build\bld.exe clear_cache
|
||||
build\bld.exe
|
||||
rem build\bld.exe cc=clang
|
||||
|
||||
@@ -58,7 +58,6 @@ int main(int argc, char **argv) {
|
||||
Array<S8_String> flags = {scratch};
|
||||
flags += "-g -Wno-write-strings";
|
||||
flags += "-fdiagnostics-absolute-paths";
|
||||
flags += "-fsanitize=address";
|
||||
if (is_cpp) flags += "-fno-exceptions";
|
||||
if (is_cpp) flags += "-fno-rtti";
|
||||
if (is_cpp) flags += "-std=c++11";
|
||||
|
||||
@@ -12,9 +12,8 @@
|
||||
#define AND_CL_STRING_TERMINATE_ON_NEW_LINE
|
||||
#include "../standalone_libraries/clexer.c"
|
||||
|
||||
MA_Arena PernamentArena;
|
||||
MA_Arena *Perm = &PernamentArena;
|
||||
Table<S8_String> CMDLine;
|
||||
thread_local MA_Arena PernamentArena;
|
||||
thread_local MA_Arena *Perm = &PernamentArena;
|
||||
|
||||
#include "cache.cpp"
|
||||
#include "easy_strings.cpp"
|
||||
|
||||
@@ -7,16 +7,7 @@ int main(int argument_count, char **arguments) {
|
||||
IO_Printf("WORKING DIR: %.*s\n", S8_Expand(working_dir));
|
||||
|
||||
Array<S8_String> cmd = CMD_Make(arguments, argument_count);
|
||||
if (CMD_Match(cmd, "clear_cache")) {
|
||||
for (OS_FileIter it = OS_IterateFiles(Perm, "./"); OS_IsValid(it); OS_Advance(&it)) {
|
||||
if (!it.is_directory && S8_EndsWith(it.filename, ".cache", true)) {
|
||||
OS_DeleteFile(it.absolute_path);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
S8_String cc = CMD_Get(cmd, "cc", IF_WINDOWS("cl") IF_MAC("clang") IF_LINUX("gcc"));
|
||||
S8_String cc = CMD_Get(cmd, "cc", IF_WINDOWS("cl") IF_MAC("clang") IF_LINUX("gcc"));
|
||||
|
||||
// Search for build file in the project directory
|
||||
S8_String build_file = {};
|
||||
@@ -31,45 +22,41 @@ int main(int argument_count, char **arguments) {
|
||||
IO_Printf("Couldnt find build file in current dir: %.*s, exiting ... \n", S8_Expand(working_dir));
|
||||
IO_Printf("- Proper build file contains 'build_file.c' in it's name\n");
|
||||
IO_Printf("- Alternative compiler can be chosen like this: bld cc=clang\n");
|
||||
IO_Printf("- Cache can be cleared like this: bld clear_cache\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
SRC_InitCache(Perm, "build_tool.cache");
|
||||
S8_String name_no_ext = S8_GetNameNoExt(build_file);
|
||||
S8_String exe_name = S8_Format(Perm, "%.*s.exe", S8_Expand(name_no_ext));
|
||||
S8_String exe_name = S8_Format(Perm, "%.*s.exe", S8_Expand(name_no_ext));
|
||||
|
||||
// Compile the build file only if code changed
|
||||
if (SRC_WasModified(build_file, exe_name)) {
|
||||
double time = OS_GetTime();
|
||||
int result = 0;
|
||||
double time = OS_GetTime();
|
||||
int result = 0;
|
||||
if (cc == "cl") {
|
||||
Array<S8_String> flags = {Perm};
|
||||
flags += "-nologo -Zi";
|
||||
flags += "-WX -W3 -wd4200 -diagnostics:column";
|
||||
flags += Fmt("/Fe:%.*s", S8_Expand(exe_name));
|
||||
flags += Fmt("/Fe:%.*s /Fd:%.*s.pdb", S8_Expand(exe_name), S8_Expand(exe_name));
|
||||
result = Run(cc + build_file + flags);
|
||||
}
|
||||
else if (cc == "clang") {
|
||||
} else if (cc == "clang") {
|
||||
Array<S8_String> flags = {Perm};
|
||||
cc = "clang++";
|
||||
|
||||
flags += "-std=c++11 -g";
|
||||
flags += "-fdiagnostics-absolute-paths";
|
||||
flags += "-Wno-writable-strings";
|
||||
flags += "-fno-exceptions";
|
||||
flags += "-fno-rtti";
|
||||
flags += "-lm";
|
||||
flags += Fmt("-o %.*s", S8_Expand(exe_name));
|
||||
result = Run(cc + build_file + flags);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
IO_Assert(cc == "gcc");
|
||||
cc = "g++";
|
||||
|
||||
Array<S8_String> flags = {Perm};
|
||||
flags += "-std=c++11 -g";
|
||||
flags += "-Wno-write-strings";
|
||||
flags += "-fno-exceptions";
|
||||
flags += "-fno-rtti";
|
||||
flags += "-lm";
|
||||
flags += Fmt("-o %.*s", S8_Expand(exe_name));
|
||||
result = Run(cc + build_file + flags);
|
||||
@@ -77,6 +64,7 @@ int main(int argument_count, char **arguments) {
|
||||
|
||||
if (result != 0) {
|
||||
IO_Printf("FAILED compilation of the build file!\n");
|
||||
OS_DeleteFile("build_tool.cache");
|
||||
return 1;
|
||||
}
|
||||
time = OS_GetTime() - time;
|
||||
@@ -86,10 +74,11 @@ int main(int argument_count, char **arguments) {
|
||||
// Run the build file
|
||||
double time = OS_GetTime();
|
||||
if (build_file.str) {
|
||||
exe_name = OS_GetAbsolutePath(Perm, exe_name);
|
||||
exe_name = OS_GetAbsolutePath(Perm, exe_name);
|
||||
int result = Run(exe_name + cmd);
|
||||
if (result != 0) {
|
||||
IO_Printf("FAILED execution of the build file!\n");
|
||||
OS_DeleteFile("build_tool.cache");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
108
core/cmd.c
108
core/cmd.c
@@ -1,6 +1,6 @@
|
||||
|
||||
CmdParser MakeCmdParser(MA_Arena *arena, int argc, char **argv) {
|
||||
CmdParser result = {argc, argv, arena};
|
||||
CmdParser MakeCmdParser(MA_Arena *arena, int argc, char **argv, const char *custom_help) {
|
||||
CmdParser result = {argc, argv, arena, custom_help};
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,15 @@ void AddBool(CmdParser *p, bool *result, const char *name, const char *help) {
|
||||
SLL_QUEUE_ADD(p->fdecl, p->ldecl, decl);
|
||||
}
|
||||
|
||||
void AddInt(CmdParser *p, int *result, const char *name, const char *help) {
|
||||
CmdDecl *decl = MA_PushStruct(p->arena, CmdDecl);
|
||||
decl->kind = CmdDeclKind_Int;
|
||||
decl->name = S8_MakeFromChar((char *)name);
|
||||
decl->help = S8_MakeFromChar((char *)help);
|
||||
decl->int_result = result;
|
||||
SLL_QUEUE_ADD(p->fdecl, p->ldecl, decl);
|
||||
}
|
||||
|
||||
void AddList(CmdParser *p, S8_List *result, const char *name, const char *help) {
|
||||
CmdDecl *decl = MA_PushStruct(p->arena, CmdDecl);
|
||||
decl->kind = CmdDeclKind_List;
|
||||
@@ -54,8 +63,9 @@ S8_String StrEnumValues(MA_Arena *arena, CmdDecl *decl) {
|
||||
}
|
||||
|
||||
void PrintCmdUsage(CmdParser *p) {
|
||||
IO_Printf("\nhere are the supported commands:\n");
|
||||
IO_Printf("%s\nCommands:\n", p->custom_help);
|
||||
for (CmdDecl *it = p->fdecl; it; it = it->next) {
|
||||
IO_Printf(" ");
|
||||
if (it->kind == CmdDeclKind_List) {
|
||||
S8_String example = S8_Format(p->arena, "-%.*s a b c", S8_Expand(it->name));
|
||||
IO_Printf("%-30.*s %.*s\n", S8_Expand(example), S8_Expand(it->help));
|
||||
@@ -64,7 +74,10 @@ void PrintCmdUsage(CmdParser *p) {
|
||||
IO_Printf("%-30.*s %.*s\n", S8_Expand(example), S8_Expand(it->help));
|
||||
} else if (it->kind == CmdDeclKind_Enum) {
|
||||
S8_String enum_vals = StrEnumValues(p->arena, it);
|
||||
S8_String example = S8_Format(p->arena, "-%.*s %.*s", S8_Expand(it->name), S8_Expand(enum_vals));
|
||||
S8_String example = S8_Format(p->arena, "-%.*s %.*s", S8_Expand(it->name), S8_Expand(enum_vals));
|
||||
IO_Printf("%-30.*s %.*s\n", S8_Expand(example), S8_Expand(it->help));
|
||||
} else if (it->kind == CmdDeclKind_Int) {
|
||||
S8_String example = S8_Format(p->arena, "-%.*s 8", S8_Expand(it->name));
|
||||
IO_Printf("%-30.*s %.*s\n", S8_Expand(example), S8_Expand(it->help));
|
||||
} else IO_Todo();
|
||||
}
|
||||
@@ -72,7 +85,6 @@ void PrintCmdUsage(CmdParser *p) {
|
||||
|
||||
bool InvalidCmdArg(CmdParser *p, S8_String arg) {
|
||||
IO_Printf("invalid command line argument: %.*s\n", S8_Expand(arg));
|
||||
PrintCmdUsage(p);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -96,8 +108,26 @@ bool ParseCmd(MA_Arena *arg_arena, CmdParser *p) {
|
||||
|
||||
if (decl->kind == CmdDeclKind_Bool) {
|
||||
*decl->bool_result = !*decl->bool_result;
|
||||
} else if (decl->kind == CmdDeclKind_Int) {
|
||||
if (i + 1 >= p->argc) {
|
||||
IO_Printf("expected at least 1 argument after %.*s\n", S8_Expand(arg));
|
||||
return false;
|
||||
}
|
||||
S8_String num = S8_MakeFromChar(p->argv[++i]);
|
||||
for (int i = 0; i < num.len; i += 1) {
|
||||
if (!CHAR_IsDigit(num.str[i])) {
|
||||
IO_Printf("expected argument to be a number, got instead: %.*s", S8_Expand(num));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int count = atoi(num.str);
|
||||
decl->int_result[0] = count;
|
||||
|
||||
} else if (decl->kind == CmdDeclKind_Enum) {
|
||||
if (i + 1 >= p->argc) { IO_Printf("expected at least 1 argument after %.*s\n", S8_Expand(arg)); PrintCmdUsage(p); return false; }
|
||||
if (i + 1 >= p->argc) {
|
||||
IO_Printf("expected at least 1 argument after %.*s\n", S8_Expand(arg));
|
||||
return false;
|
||||
}
|
||||
S8_String option_from_cmd = S8_MakeFromChar(p->argv[++i]);
|
||||
|
||||
bool found_option = false;
|
||||
@@ -105,7 +135,7 @@ bool ParseCmd(MA_Arena *arg_arena, CmdParser *p) {
|
||||
S8_String option = S8_MakeFromChar((char *)decl->enum_options[i]);
|
||||
if (S8_AreEqual(option, option_from_cmd, true)) {
|
||||
*decl->enum_result = i;
|
||||
found_option = true;
|
||||
found_option = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -113,18 +143,23 @@ bool ParseCmd(MA_Arena *arg_arena, CmdParser *p) {
|
||||
if (!found_option) {
|
||||
IO_Printf("expected one of the enum values: %.*s", S8_Expand(StrEnumValues(p->arena, decl)));
|
||||
IO_Printf(" got instead: %.*s\n", S8_Expand(option_from_cmd));
|
||||
PrintCmdUsage(p);
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (decl->kind == CmdDeclKind_List) {
|
||||
if (i + 1 >= p->argc) { IO_Printf("expected at least 1 argument after %.*s\n", S8_Expand(arg)); PrintCmdUsage(p); return false; }
|
||||
if (i + 1 >= p->argc) {
|
||||
IO_Printf("expected at least 1 argument after %.*s\n", S8_Expand(arg));
|
||||
return false;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
for (int counter = 0; i < p->argc; i += 1, counter += 1) {
|
||||
S8_String arg = S8_MakeFromChar(p->argv[i]);
|
||||
if (arg.str[0] == '-') {
|
||||
if (counter == 0) { IO_Printf("expected at least 1 argument after %.*s\n", S8_Expand(arg)); PrintCmdUsage(p); return false; }
|
||||
if (counter == 0) {
|
||||
IO_Printf("expected at least 1 argument after %.*s\n", S8_Expand(arg));
|
||||
return false;
|
||||
}
|
||||
i -= 1;
|
||||
break;
|
||||
}
|
||||
@@ -133,48 +168,19 @@ bool ParseCmd(MA_Arena *arg_arena, CmdParser *p) {
|
||||
}
|
||||
} else IO_Todo();
|
||||
|
||||
} else {
|
||||
if (p->require_one_standalone_arg && p->args.node_count == 0) {
|
||||
S8_AddNode(arg_arena, &p->args, arg);
|
||||
} else {
|
||||
return InvalidCmdArg(p, arg);
|
||||
}
|
||||
}
|
||||
else return InvalidCmdArg(p, arg);
|
||||
}
|
||||
|
||||
if (p->require_one_standalone_arg && p->args.node_count == 0) {
|
||||
PrintCmdUsage(p);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ./a.exe -scratch
|
||||
// ./a.exe -quick
|
||||
// ./a.exe -run_tests a.test b.test c.test
|
||||
// ./a.exe --break_on_error
|
||||
// ./a.exe -build=release
|
||||
// ./a.exe --help
|
||||
//
|
||||
void TestCmdParser() {
|
||||
char *argv[] = {
|
||||
"exe",
|
||||
"--build_scratch",
|
||||
"-tests",
|
||||
"a", "b", "c",
|
||||
"--things", "1234", "asdsa",
|
||||
"-build", "release",
|
||||
};
|
||||
int argc = MA_Lengthof(argv);
|
||||
|
||||
MA_Checkpoint scratch = MA_GetScratch();
|
||||
bool build_scratch = false;
|
||||
S8_List test_list = {0};
|
||||
S8_List test_things = {0};
|
||||
int build_profile = 0;
|
||||
const char *build_profiles[] = {"debug", "release"};
|
||||
int build_profiles_count = MA_Lengthof(build_profiles);
|
||||
|
||||
CmdParser p = MakeCmdParser(scratch.arena, argc, argv);
|
||||
AddBool(&p, &build_scratch, "build_scratch", "builds a sandbox where I experiment with things");
|
||||
AddList(&p, &test_list, "tests", "list of specific tests to run");
|
||||
AddList(&p, &test_things, "things", "list of things");
|
||||
AddEnum(&p, &build_profile, "build", "choose build profile", build_profiles, build_profiles_count);
|
||||
bool success = ParseCmd(scratch.arena, &p);
|
||||
IO_Assertf(success, "failed to parse cmd");
|
||||
IO_Assert(build_scratch);
|
||||
IO_Assert(test_list.node_count == 3);
|
||||
IO_Assert(test_things.node_count == 2);
|
||||
IO_Assert(build_profile == 1);
|
||||
MA_ReleaseScratch(scratch);
|
||||
}
|
||||
|
||||
16
core/cmd.h
16
core/cmd.h
@@ -1,6 +1,7 @@
|
||||
|
||||
typedef enum {
|
||||
CmdDeclKind_Bool,
|
||||
CmdDeclKind_Int,
|
||||
CmdDeclKind_List,
|
||||
CmdDeclKind_Enum,
|
||||
} CmdDeclKind;
|
||||
@@ -14,6 +15,7 @@ struct CmdDecl {
|
||||
|
||||
bool *bool_result;
|
||||
S8_List *list_result;
|
||||
int *int_result;
|
||||
|
||||
int *enum_result;
|
||||
const char **enum_options;
|
||||
@@ -22,10 +24,14 @@ struct CmdDecl {
|
||||
|
||||
typedef struct CmdParser CmdParser;
|
||||
struct CmdParser {
|
||||
int argc;
|
||||
char **argv;
|
||||
MA_Arena *arena;
|
||||
int argc;
|
||||
char **argv;
|
||||
MA_Arena *arena;
|
||||
const char *custom_help;
|
||||
|
||||
CmdDecl *fdecl;
|
||||
CmdDecl *ldecl;
|
||||
CmdDecl *fdecl;
|
||||
CmdDecl *ldecl;
|
||||
|
||||
bool require_one_standalone_arg;
|
||||
S8_List args;
|
||||
};
|
||||
|
||||
@@ -20,11 +20,3 @@
|
||||
#include "filesystem.c"
|
||||
|
||||
#include "cmd.c"
|
||||
|
||||
/*
|
||||
- I think it's okay to say that strings being null terminated should be mostly treated as NOT terminated but leave some
|
||||
leeway for big buffers and other such things. Just make sure to not relay on it because it's easier unless specified.
|
||||
- Not sure if we should assume that strings should use allocators or arenas, for now it's arenas because I don't have other use cases
|
||||
@todo
|
||||
- Remove static buffers from filesystem, use scratch arenas, more secure, data corruption instead of control flow corruption
|
||||
*/
|
||||
|
||||
@@ -381,7 +381,7 @@ OS_API OS_Date OS_GetDate(void) {
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
#elif __linux__ || __APPLE__ || __unix__
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -690,9 +690,9 @@ OS_API OS_Result OS_WriteFile(S8_String path, S8_String string) {
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if _WIN32 || __linux__ || __APPLE__ || __unix__
|
||||
OS_API int OS_SystemF(const char *string, ...) {
|
||||
MA_Checkpoint scratch = MA_GetScratch();
|
||||
S8_FORMAT(scratch.arena, string, result);
|
||||
@@ -746,3 +746,4 @@ OS_API S8_String OS_ExpandIncludes(MA_Arena *arena, S8_String filepath) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
@@ -4,20 +4,6 @@
|
||||
#define MA_Assertf(x, ...) assert(x)
|
||||
#endif
|
||||
|
||||
#ifndef MA_MemoryZero
|
||||
#include <string.h>
|
||||
MA_API void MA_MemoryZero(void *p, size_t size) {
|
||||
memset(p, 0, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef MA_MemoryCopy
|
||||
#include <string.h>
|
||||
MA_API void MA_MemoryCopy(void *dst, void *src, size_t size) {
|
||||
memcpy(dst, src, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef MA_CMalloc
|
||||
#include <stdlib.h>
|
||||
#define MA_CMalloc(x) malloc(x)
|
||||
@@ -41,14 +27,14 @@ MA_API void MA_MemoryCopy(void *dst, void *src, size_t size) {
|
||||
#endif
|
||||
|
||||
MA_THREAD_LOCAL MA_SourceLoc MA_SavedSourceLoc;
|
||||
MA_API void MA_SaveSourceLocEx(const char *file, int line) {
|
||||
MA_API void MA_SaveSourceLocEx(const char *file, int line) {
|
||||
MA_SavedSourceLoc.file = file;
|
||||
MA_SavedSourceLoc.line = line;
|
||||
}
|
||||
|
||||
MA_API size_t MA_GetAlignOffset(size_t size, size_t align) {
|
||||
size_t mask = align - 1;
|
||||
size_t val = size & mask;
|
||||
size_t val = size & mask;
|
||||
if (val) {
|
||||
val = align - val;
|
||||
}
|
||||
@@ -67,10 +53,10 @@ MA_API size_t MA_AlignDown(size_t size, size_t align) {
|
||||
}
|
||||
|
||||
MA_StaticFunc uint8_t *MV__AdvanceCommit(MV_Memory *m, size_t *commit_size, size_t page_size) {
|
||||
size_t aligned_up_commit = MA_AlignUp(*commit_size, page_size);
|
||||
size_t to_be_total_commited_size = aligned_up_commit + m->commit;
|
||||
size_t aligned_up_commit = MA_AlignUp(*commit_size, page_size);
|
||||
size_t to_be_total_commited_size = aligned_up_commit + m->commit;
|
||||
size_t to_be_total_commited_size_clamped_to_reserve = MA_CLAMP_TOP(to_be_total_commited_size, m->reserve);
|
||||
size_t adjusted_to_boundary_commit = to_be_total_commited_size_clamped_to_reserve - m->commit;
|
||||
size_t adjusted_to_boundary_commit = to_be_total_commited_size_clamped_to_reserve - m->commit;
|
||||
MA_Assertf(adjusted_to_boundary_commit, "Reached the virtual memory reserved boundary");
|
||||
*commit_size = adjusted_to_boundary_commit;
|
||||
|
||||
@@ -83,9 +69,9 @@ MA_StaticFunc uint8_t *MV__AdvanceCommit(MV_Memory *m, size_t *commit_size, size
|
||||
|
||||
MA_API void MA_PopToPos(MA_Arena *arena, size_t pos) {
|
||||
MA_Assertf(arena->len >= arena->base_len, "Bug: arena->len shouldn't ever be smaller then arena->base_len");
|
||||
pos = MA_CLAMP(pos, arena->base_len, arena->len);
|
||||
pos = MA_CLAMP(pos, arena->base_len, arena->len);
|
||||
size_t size = arena->len - pos;
|
||||
arena->len = pos;
|
||||
arena->len = pos;
|
||||
ASAN_POISON_MEMORY_REGION(arena->memory.data + arena->len, size);
|
||||
}
|
||||
|
||||
@@ -103,7 +89,7 @@ MA_API void MA_Reset(MA_Arena *arena) {
|
||||
|
||||
MA_StaticFunc size_t MA__AlignLen(MA_Arena *a) {
|
||||
size_t align_offset = a->alignment ? MA_GetAlignOffset((uintptr_t)a->memory.data + (uintptr_t)a->len, a->alignment) : 0;
|
||||
size_t aligned = a->len + align_offset;
|
||||
size_t aligned = a->len + align_offset;
|
||||
return aligned;
|
||||
}
|
||||
|
||||
@@ -117,8 +103,8 @@ MA_API uint8_t *MA_GetTop(MA_Arena *a) {
|
||||
}
|
||||
|
||||
MA_API void *MA__PushSizeNonZeroed(MA_Arena *a, size_t size) {
|
||||
size_t align_offset = a->alignment ? MA_GetAlignOffset((uintptr_t)a->memory.data + (uintptr_t)a->len, a->alignment) : 0;
|
||||
size_t aligned_len = a->len + align_offset;
|
||||
size_t align_offset = a->alignment ? MA_GetAlignOffset((uintptr_t)a->memory.data + (uintptr_t)a->len, a->alignment) : 0;
|
||||
size_t aligned_len = a->len + align_offset;
|
||||
size_t size_with_alignment = size + align_offset;
|
||||
|
||||
if (a->len + size_with_alignment > a->memory.commit) {
|
||||
@@ -163,10 +149,10 @@ MA_API void *MA__PushCopy(MA_Arena *arena, void *p, size_t size) {
|
||||
MA_API MA_Arena MA_PushArena(MA_Arena *arena, size_t size) {
|
||||
MA_Arena result;
|
||||
MA_MemoryZero(&result, sizeof(result));
|
||||
result.memory.data = MA_PushArrayNonZeroed(arena, uint8_t, size);
|
||||
result.memory.commit = size;
|
||||
result.memory.data = MA_PushArrayNonZeroed(arena, uint8_t, size);
|
||||
result.memory.commit = size;
|
||||
result.memory.reserve = size;
|
||||
result.alignment = arena->alignment;
|
||||
result.alignment = arena->alignment;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -187,26 +173,26 @@ MA_API void MA_MakeSureInitialized(MA_Arena *a) {
|
||||
}
|
||||
|
||||
MA_API MA_Arena *MA_Bootstrap(void) {
|
||||
MA_Arena bootstrap_arena = {0};
|
||||
MA_Arena *arena = MA_PushStruct(&bootstrap_arena, MA_Arena);
|
||||
*arena = bootstrap_arena;
|
||||
arena->base_len = arena->len;
|
||||
MA_Arena bootstrap_arena = {0};
|
||||
MA_Arena *arena = MA_PushStruct(&bootstrap_arena, MA_Arena);
|
||||
*arena = bootstrap_arena;
|
||||
arena->base_len = arena->len;
|
||||
return arena;
|
||||
}
|
||||
|
||||
MA_API M_Allocator MA_BootstrapExclusive(void) {
|
||||
MA_Arena bootstrap_arena = {0};
|
||||
MA_Arena *arena = MA_PushStruct(&bootstrap_arena, MA_Arena);
|
||||
*arena = bootstrap_arena;
|
||||
arena->base_len = arena->len;
|
||||
MA_Arena bootstrap_arena = {0};
|
||||
MA_Arena *arena = MA_PushStruct(&bootstrap_arena, MA_Arena);
|
||||
*arena = bootstrap_arena;
|
||||
arena->base_len = arena->len;
|
||||
return MA_GetExclusiveAllocator(arena);
|
||||
}
|
||||
|
||||
MA_API void MA_InitFromBuffer(MA_Arena *arena, void *buffer, size_t size) {
|
||||
arena->memory.data = (uint8_t *)buffer;
|
||||
arena->memory.commit = size;
|
||||
arena->memory.data = (uint8_t *)buffer;
|
||||
arena->memory.commit = size;
|
||||
arena->memory.reserve = size;
|
||||
arena->alignment = MA_DEFAULT_ALIGNMENT;
|
||||
arena->alignment = MA_DEFAULT_ALIGNMENT;
|
||||
ASAN_POISON_MEMORY_REGION(arena->memory.data, arena->memory.reserve);
|
||||
}
|
||||
|
||||
@@ -225,15 +211,15 @@ MA_API MA_Arena MA_Create() {
|
||||
|
||||
MA_API bool MA_IsPointerInside(MA_Arena *arena, void *p) {
|
||||
uintptr_t pointer = (uintptr_t)p;
|
||||
uintptr_t start = (uintptr_t)arena->memory.data;
|
||||
uintptr_t stop = start + (uintptr_t)arena->len;
|
||||
bool result = pointer >= start && pointer < stop;
|
||||
uintptr_t start = (uintptr_t)arena->memory.data;
|
||||
uintptr_t stop = start + (uintptr_t)arena->len;
|
||||
bool result = pointer >= start && pointer < stop;
|
||||
return result;
|
||||
}
|
||||
|
||||
MA_API MA_Checkpoint MA_Save(MA_Arena *arena) {
|
||||
MA_Checkpoint result;
|
||||
result.pos = arena->len;
|
||||
result.pos = arena->len;
|
||||
result.arena = arena;
|
||||
return result;
|
||||
}
|
||||
@@ -311,7 +297,7 @@ MA_API void *MA_ExclusiveAllocatorProc(void *allocator, M_AllocatorOp kind, void
|
||||
if (kind == M_AllocatorOp_Reallocate) {
|
||||
if (size > old_size) {
|
||||
size_t size_to_push = size - old_size;
|
||||
void *result = MA__PushSizeNonZeroed(arena, size_to_push);
|
||||
void *result = MA__PushSizeNonZeroed(arena, size_to_push);
|
||||
if (!p) p = result;
|
||||
return p;
|
||||
}
|
||||
@@ -339,7 +325,7 @@ MA_API M_Allocator MA_GetAllocator(MA_Arena *arena) {
|
||||
MA_API M_Allocator M_GetSystemAllocator(void) {
|
||||
M_Allocator allocator;
|
||||
allocator.obj = 0;
|
||||
allocator.p = M_ClibAllocatorProc;
|
||||
allocator.p = M_ClibAllocatorProc;
|
||||
return allocator;
|
||||
}
|
||||
|
||||
@@ -350,7 +336,7 @@ MA_API MA_Checkpoint MA_GetScratchEx(MA_Arena **conflicts, int conflict_count) {
|
||||
MA_Arena *unoccupied = 0;
|
||||
for (int i = 0; i < MA_Lengthof(MA_ScratchArenaPool); i += 1) {
|
||||
MA_Arena *from_pool = MA_ScratchArenaPool + i;
|
||||
unoccupied = from_pool;
|
||||
unoccupied = from_pool;
|
||||
for (int conflict_i = 0; conflict_i < conflict_count; conflict_i += 1) {
|
||||
MA_Arena *from_conflict = conflicts[conflict_i];
|
||||
if (from_pool == from_conflict) {
|
||||
@@ -395,7 +381,7 @@ MA_API MV_Memory MV_Reserve(size_t size) {
|
||||
MV_Memory result;
|
||||
MA_MemoryZero(&result, sizeof(result));
|
||||
size_t adjusted_size = MA_AlignUp(size, MV__WIN32_PAGE_SIZE);
|
||||
result.data = (uint8_t *)VirtualAlloc(0, adjusted_size, MEM_RESERVE, PAGE_READWRITE);
|
||||
result.data = (uint8_t *)VirtualAlloc(0, adjusted_size, MEM_RESERVE, PAGE_READWRITE);
|
||||
MA_Assertf(result.data, "Failed to reserve virtual memory");
|
||||
result.reserve = adjusted_size;
|
||||
return result;
|
||||
@@ -420,12 +406,12 @@ MA_API void MV_Deallocate(MV_Memory *m) {
|
||||
}
|
||||
|
||||
MA_API bool MV_DecommitPos(MV_Memory *m, size_t pos) {
|
||||
size_t aligned = MA_AlignDown(pos, MV__WIN32_PAGE_SIZE);
|
||||
size_t adjusted_pos = MA_CLAMP_TOP(aligned, m->commit);
|
||||
size_t aligned = MA_AlignDown(pos, MV__WIN32_PAGE_SIZE);
|
||||
size_t adjusted_pos = MA_CLAMP_TOP(aligned, m->commit);
|
||||
size_t size_to_decommit = m->commit - adjusted_pos;
|
||||
if (size_to_decommit) {
|
||||
uint8_t *base_address = m->data + adjusted_pos;
|
||||
BOOL result = VirtualFree(base_address, size_to_decommit, MEM_DECOMMIT);
|
||||
BOOL result = VirtualFree(base_address, size_to_decommit, MEM_DECOMMIT);
|
||||
if (result) {
|
||||
m->commit -= size_to_decommit;
|
||||
return true;
|
||||
@@ -434,7 +420,7 @@ MA_API bool MV_DecommitPos(MV_Memory *m, size_t pos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
#elif __unix__ || __linux__ || __APPLE__
|
||||
#include <sys/mman.h>
|
||||
#define MV__UNIX_PAGE_SIZE 4096
|
||||
MA_API MV_Memory MV_Reserve(size_t size) {
|
||||
@@ -465,4 +451,17 @@ MA_API void MV_Deallocate(MV_Memory *m) {
|
||||
int result = munmap(m->data, m->reserve);
|
||||
MA_Assertf(result == 0, "Failed to release virtual memory using munmap");
|
||||
}
|
||||
#else
|
||||
MA_API MV_Memory MV_Reserve(size_t size) {
|
||||
MV_Memory result = {0};
|
||||
return result;
|
||||
}
|
||||
|
||||
MA_API bool MV_Commit(MV_Memory *m, size_t commit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MA_API void MV_Deallocate(MV_Memory *m) {
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -55,6 +55,16 @@ typedef struct MA_SourceLoc MA_SourceLoc;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MA_MemoryZero
|
||||
#include <string.h>
|
||||
#define MA_MemoryZero(p, size) memset(p, 0, size)
|
||||
#endif
|
||||
|
||||
#ifndef MA_MemoryCopy
|
||||
#include <string.h>
|
||||
#define MA_MemoryCopy(dst, src, size) memcpy(dst, src, size);
|
||||
#endif
|
||||
|
||||
typedef enum M_AllocatorOp {
|
||||
M_AllocatorOp_Invalid,
|
||||
M_AllocatorOp_Allocate,
|
||||
@@ -158,8 +168,6 @@ MA_API void MA_PopSize(MA_Arena *arena, size_t size);
|
||||
MA_API void MA_DeallocateArena(MA_Arena *arena);
|
||||
MA_API void MA_Reset(MA_Arena *arena);
|
||||
|
||||
MA_API void MA_MemoryZero(void *p, size_t size);
|
||||
MA_API void MA_MemoryCopy(void *dst, void *src, size_t size);
|
||||
MA_API size_t MA_GetAlignOffset(size_t size, size_t align);
|
||||
MA_API size_t MA_AlignUp(size_t size, size_t align);
|
||||
MA_API size_t MA_AlignDown(size_t size, size_t align);
|
||||
|
||||
@@ -31,19 +31,19 @@ IO_StaticFunc int IO_Strlen(char *string) {
|
||||
return len;
|
||||
}
|
||||
|
||||
void (*IO_User_OutputMessage)(int kind, const char *file, int line, char *str, int len);
|
||||
IO_THREAD_LOCAL void (*IO_User_OutputMessage)(int kind, const char *file, int line, char *str, int len);
|
||||
|
||||
IO_API bool IO__FatalErrorf(const char *file, int line, const char *msg, ...) {
|
||||
va_list args1;
|
||||
va_list args2;
|
||||
char buff[2048];
|
||||
char buff[2048];
|
||||
|
||||
va_start(args1, msg);
|
||||
va_copy(args2, args1);
|
||||
int size = IO_VSNPRINTF(buff, sizeof(buff), msg, args2);
|
||||
va_end(args2);
|
||||
|
||||
char *new_buffer = 0;
|
||||
char *new_buffer = 0;
|
||||
char *user_message = buff;
|
||||
if (size >= sizeof(buff)) {
|
||||
size += 4;
|
||||
@@ -55,14 +55,14 @@ IO_API bool IO__FatalErrorf(const char *file, int line, const char *msg, ...) {
|
||||
|
||||
IO_ErrorResult ret = IO_ErrorResult_Continue;
|
||||
{
|
||||
char buff2[2048];
|
||||
char buff2[2048];
|
||||
char *result = buff2;
|
||||
char *b = 0;
|
||||
int size2 = IO_SNPRINTF(buff2, sizeof(buff2), "%s(%d): error: %s \n", file, line, user_message);
|
||||
char *b = 0;
|
||||
int size2 = IO_SNPRINTF(buff2, sizeof(buff2), "%s(%d): error: %s \n", file, line, user_message);
|
||||
if (size2 >= sizeof(buff2)) {
|
||||
size2 += 4;
|
||||
b = (char *)IO_ALLOCATE(size2);
|
||||
size2 = IO_SNPRINTF(b, size2, "%s(%d): error: %s \n", file, line, user_message);
|
||||
b = (char *)IO_ALLOCATE(size2);
|
||||
size2 = IO_SNPRINTF(b, size2, "%s(%d): error: %s \n", file, line, user_message);
|
||||
result = b;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ IO_API void IO__Printf(int kind, const char *file, int line, const char *msg, ..
|
||||
// case.
|
||||
va_list args1;
|
||||
va_list args2;
|
||||
char buff[2048];
|
||||
char buff[2048];
|
||||
|
||||
va_start(args1, msg);
|
||||
va_copy(args2, args1);
|
||||
@@ -97,7 +97,7 @@ IO_API void IO__Printf(int kind, const char *file, int line, const char *msg, ..
|
||||
va_end(args2);
|
||||
|
||||
char *new_buffer = 0;
|
||||
char *result = buff;
|
||||
char *result = buff;
|
||||
if (size >= sizeof(buff)) {
|
||||
size += 4;
|
||||
new_buffer = (char *)IO_ALLOCATE(size);
|
||||
@@ -108,8 +108,7 @@ IO_API void IO__Printf(int kind, const char *file, int line, const char *msg, ..
|
||||
|
||||
if (IO_User_OutputMessage) {
|
||||
IO_User_OutputMessage(kind, file, line, result, size);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
IO_OutputMessage(result, size);
|
||||
}
|
||||
|
||||
@@ -118,9 +117,9 @@ IO_API void IO__Printf(int kind, const char *file, int line, const char *msg, ..
|
||||
}
|
||||
}
|
||||
|
||||
IO_API bool IO__FatalError(char *msg) {
|
||||
int len = IO_Strlen(msg);
|
||||
IO_ErrorResult result = IO_OutputError(msg, len);
|
||||
IO_API bool IO__FatalError(const char *msg) {
|
||||
int len = IO_Strlen((char *)msg);
|
||||
IO_ErrorResult result = IO_OutputError((char *)msg, len);
|
||||
if (result == IO_ErrorResult_Exit) {
|
||||
IO_Exit(1);
|
||||
}
|
||||
@@ -130,8 +129,7 @@ IO_API bool IO__FatalError(char *msg) {
|
||||
IO_API void IO_Print(int kind, const char *file, int line, char *msg, int len) {
|
||||
if (IO_User_OutputMessage) {
|
||||
IO_User_OutputMessage(kind, file, line, msg, len);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
IO_OutputMessage(msg, len);
|
||||
}
|
||||
}
|
||||
@@ -177,7 +175,7 @@ IO_API IO_ErrorResult IO_OutputError(char *str, int len) {
|
||||
// Limit size of error output message
|
||||
char tmp = 0;
|
||||
if (len > 4096) {
|
||||
tmp = str[4096];
|
||||
tmp = str[4096];
|
||||
str[4096] = 0;
|
||||
}
|
||||
|
||||
@@ -188,8 +186,7 @@ IO_API IO_ErrorResult IO_OutputError(char *str, int len) {
|
||||
}
|
||||
|
||||
result = IO_ErrorResult_Exit;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
result = IO_ErrorResult_Break;
|
||||
}
|
||||
|
||||
@@ -203,9 +200,8 @@ IO_API IO_ErrorResult IO_OutputError(char *str, int len) {
|
||||
IO_API void IO_Exit(int error_code) {
|
||||
ExitProcess(error_code);
|
||||
}
|
||||
#else // _WIN32 else // LIBC
|
||||
#elif __linux__ || __unix__ || __APPLE__
|
||||
#include <stdio.h>
|
||||
|
||||
IO_API IO_ErrorResult IO_OutputError(char *str, int len) {
|
||||
fprintf(stderr, "%.*s", len, str);
|
||||
return IO_ErrorResult_Exit;
|
||||
@@ -222,4 +218,19 @@ IO_API void IO_Exit(int error_code) {
|
||||
IO_API bool IO_IsDebuggerPresent(void) {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
IO_API IO_ErrorResult IO_OutputError(char *str, int len) {
|
||||
return IO_ErrorResult_Exit;
|
||||
}
|
||||
|
||||
IO_API void IO_OutputMessage(char *str, int len) {
|
||||
}
|
||||
|
||||
IO_API void IO_Exit(int error_code) {
|
||||
}
|
||||
|
||||
IO_API bool IO_IsDebuggerPresent(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // LIBC
|
||||
|
||||
@@ -22,6 +22,22 @@ typedef enum IO_ErrorResult {
|
||||
#define IO_DebugBreak() (__builtin_trap(), 0)
|
||||
#endif
|
||||
|
||||
#ifndef IO_THREAD_LOCAL
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L
|
||||
#define IO_THREAD_LOCAL thread_local
|
||||
#elif defined(__GNUC__)
|
||||
#define IO_THREAD_LOCAL __thread
|
||||
#elif defined(_MSC_VER)
|
||||
#define IO_THREAD_LOCAL __declspec(thread)
|
||||
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
|
||||
#define IO_THREAD_LOCAL _Thread_local
|
||||
#elif defined(__TINYC__)
|
||||
#define IO_THREAD_LOCAL _Thread_local
|
||||
#else
|
||||
#error Couldnt figure out thread local, needs to be provided manually
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__has_attribute)
|
||||
#if __has_attribute(format)
|
||||
#define IO__PrintfFormat(fmt, va) __attribute__((format(printf, fmt, va)))
|
||||
@@ -33,14 +49,14 @@ typedef enum IO_ErrorResult {
|
||||
#endif
|
||||
|
||||
typedef void IO_MessageHandler(int kind, const char *file, int line, char *str, int len);
|
||||
extern void (*IO_User_OutputMessage)(int kind, const char *file, int line, char *str, int len);
|
||||
extern IO_THREAD_LOCAL void (*IO_User_OutputMessage)(int kind, const char *file, int line, char *str, int len);
|
||||
|
||||
#define IO__STRINGIFY(x) #x
|
||||
#define IO__TOSTRING(x) IO__STRINGIFY(x)
|
||||
#define IO_LINE IO__TOSTRING(__LINE__)
|
||||
|
||||
#define IO_Assert(x) !(x) && IO__FatalError((char *)(__FILE__ "(" IO_LINE "): " \
|
||||
"error: " #x "\n")) && \
|
||||
#define IO_Assert(x) !(x) && IO__FatalError((__FILE__ "(" IO_LINE "): " \
|
||||
"error: " #x "\n")) && \
|
||||
IO_DebugBreak()
|
||||
#define IO_FatalErrorf(...) \
|
||||
do { \
|
||||
@@ -69,22 +85,22 @@ extern void (*IO_User_OutputMessage)(int kind, const char *file, int line, char
|
||||
IO_InvalidCodepath(); \
|
||||
}
|
||||
#define IO_InvalidCodepath() IO_FatalError("This codepath is invalid")
|
||||
#define IO_InvalidDefaultCase() \
|
||||
default: { \
|
||||
IO_FatalError("Entered invalid switch statement case"); \
|
||||
}
|
||||
#define IO_InvalidDefaultCase() \
|
||||
default: { \
|
||||
IO_FatalError("Entered invalid switch statement case"); \
|
||||
}
|
||||
#define IO_Todo() IO_FatalError("This codepath is not implemented yet")
|
||||
|
||||
IO_API bool IO__FatalErrorf(const char *file, int line, const char *msg, ...) IO__PrintfFormat(3, 4);
|
||||
IO_API void IO__Printf(int kind, const char *file, int line, const char *msg, ...) IO__PrintfFormat(4, 5);
|
||||
IO_API bool IO__FatalError(char *msg);
|
||||
IO_API void IO_Print(int kind, const char *file, int line, char *msg, int len);
|
||||
IO_API void IO_OutputMessage(char *str, int len);
|
||||
IO_API bool IO__FatalErrorf(const char *file, int line, const char *msg, ...) IO__PrintfFormat(3, 4);
|
||||
IO_API void IO__Printf(int kind, const char *file, int line, const char *msg, ...) IO__PrintfFormat(4, 5);
|
||||
IO_API bool IO__FatalError(const char *msg);
|
||||
IO_API void IO_Print(int kind, const char *file, int line, char *msg, int len);
|
||||
IO_API void IO_OutputMessage(char *str, int len);
|
||||
IO_API IO_ErrorResult IO_OutputError(char *str, int len);
|
||||
IO_API void IO_Exit(int error_code);
|
||||
IO_API bool IO_IsDebuggerPresent(void);
|
||||
IO_API void IO_Exit(int error_code);
|
||||
IO_API bool IO_IsDebuggerPresent(void);
|
||||
|
||||
static const int IO_KindPrintf = 1;
|
||||
static const int IO_KindPrintf = 1;
|
||||
static const int IO_KindWarningf = 2;
|
||||
|
||||
#define IO_Printf(...) IO__Printf(IO_KindPrintf, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#elif defined(__linux__)
|
||||
#define OS_POSIX 1
|
||||
#define OS_LINUX 1
|
||||
#elif OS_WASM
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
@@ -109,6 +110,8 @@
|
||||
#define OS_NAME "linux"
|
||||
#elif OS_MAC
|
||||
#define OS_NAME "mac_os"
|
||||
#elif OS_WASM
|
||||
#define OS_NAME "wasm"
|
||||
#else
|
||||
#error couldnt figure out OS
|
||||
#endif
|
||||
|
||||
@@ -4,6 +4,51 @@
|
||||
#include "test_arena.cpp"
|
||||
#include "test_lexer.cpp"
|
||||
|
||||
// ./a.exe -scratch
|
||||
// ./a.exe -quick
|
||||
// ./a.exe -run_tests a.test b.test c.test
|
||||
// ./a.exe --break_on_error
|
||||
// ./a.exe -build=release
|
||||
// ./a.exe --help
|
||||
//
|
||||
void TestCmdParser() {
|
||||
const char *argv[] = {
|
||||
"exe",
|
||||
"--build_scratch",
|
||||
"-tests",
|
||||
"a",
|
||||
"b",
|
||||
"c",
|
||||
"--things",
|
||||
"1234",
|
||||
"asdsa",
|
||||
"-build",
|
||||
"release",
|
||||
};
|
||||
int argc = MA_Lengthof(argv);
|
||||
|
||||
MA_Checkpoint scratch = MA_GetScratch();
|
||||
bool build_scratch = false;
|
||||
S8_List test_list = {0};
|
||||
S8_List test_things = {0};
|
||||
int build_profile = 0;
|
||||
const char *build_profiles[] = {"debug", "release"};
|
||||
int build_profiles_count = MA_Lengthof(build_profiles);
|
||||
|
||||
CmdParser p = MakeCmdParser(scratch.arena, argc, (char **)argv, "this is a test");
|
||||
AddBool(&p, &build_scratch, "build_scratch", "builds a sandbox where I experiment with things");
|
||||
AddList(&p, &test_list, "tests", "list of specific tests to run");
|
||||
AddList(&p, &test_things, "things", "list of things");
|
||||
AddEnum(&p, &build_profile, "build", "choose build profile", build_profiles, build_profiles_count);
|
||||
bool success = ParseCmd(scratch.arena, &p);
|
||||
IO_Assertf(success, "failed to parse cmd");
|
||||
IO_Assert(build_scratch);
|
||||
IO_Assert(test_list.node_count == 3);
|
||||
IO_Assert(test_things.node_count == 2);
|
||||
IO_Assert(build_profile == 1);
|
||||
MA_ReleaseScratch(scratch);
|
||||
}
|
||||
|
||||
int main() {
|
||||
TestSimpleInsertAndIntegrity();
|
||||
TestStrings();
|
||||
@@ -20,7 +65,6 @@ int main() {
|
||||
TestBootstrapExclusive();
|
||||
TestBootstrapArenaClear();
|
||||
|
||||
// @todo: github worker fails on this:
|
||||
TestClexer();
|
||||
|
||||
// Unicode iteration over codepoints using For
|
||||
@@ -40,7 +84,7 @@ int main() {
|
||||
// List iteration using For
|
||||
{
|
||||
MA_Scratch scratch;
|
||||
S8_List list = {};
|
||||
S8_List list = {};
|
||||
S8_AddF(scratch, &list, "1");
|
||||
S8_AddF(scratch, &list, "2");
|
||||
S8_AddF(scratch, &list, "3");
|
||||
|
||||
Reference in New Issue
Block a user