From 5ab1d4dab7c9f2cb46e96fb03a284b35e905eecf Mon Sep 17 00:00:00 2001 From: jacob Date: Thu, 6 Nov 2025 17:21:27 -0600 Subject: [PATCH] command line utils --- build.bat | 6 +- src/base/base.h | 2 +- src/base/base_cmdline.c | 103 +++++++++++++++++++++++++++++++ src/base/base_cmdline.h | 42 +++++++++++++ src/base/base_inc.h | 4 +- src/base/base_string.c | 6 +- src/base/base_string.h | 2 +- src/base/base_win32/base_win32.c | 28 +++++++-- src/base/base_win32/base_win32.h | 2 + src/meta/meta.c | 50 +++++++++++---- 10 files changed, 220 insertions(+), 25 deletions(-) create mode 100644 src/base/base_cmdline.c create mode 100644 src/base/base_cmdline.h diff --git a/build.bat b/build.bat index 146a5982..22c6cbc4 100644 --- a/build.bat +++ b/build.bat @@ -9,10 +9,12 @@ set program_build_cmd=meta.exe %* set meta_build_cmd=cl.exe ../src/meta/meta.c -Od -Z7 -nologo -diagnostics:column -WX -link -DEBUG:FULL -INCREMENTAL:NO set meta_rebuild_code=1317212284 -if "%force_meta_build%"=="1" ( +if "%--force_meta_build%"=="1" ( if exist meta.exe del meta.exe ) +echo build_cmd: %program_build_cmd% + ::- Meta build :meta_build if not exist meta.exe ( @@ -26,7 +28,7 @@ if not exist meta.exe ( ) ::- Program build -if not "%no_program_build%"=="1" ( +if not "%--no_program_build%"=="1" ( echo ======== Build ======== %program_build_cmd% set "rc=!errorlevel!" diff --git a/src/base/base.h b/src/base/base.h index aab6e04a..83100a0d 100644 --- a/src/base/base.h +++ b/src/base/base.h @@ -780,7 +780,7 @@ typedef ExitFuncDef(ExitFunc); #if LanguageIsC //- Core hooks -StringList GetCommandLineArgs(void); +StringList GetRawCommandline(void); void Echo(String msg); b32 Panic(String msg); b32 IsRunningInDebugger(void); diff --git a/src/base/base_cmdline.c b/src/base/base_cmdline.c new file mode 100644 index 00000000..b15fd6b6 --- /dev/null +++ b/src/base/base_cmdline.c @@ -0,0 +1,103 @@ +SharedCmdlineState shared_cmdline_state = ZI; + +//////////////////////////////////////////////////////////// +//~ Initialization + +void InitCmdline(void) +{ + SharedCmdlineState *g = &shared_cmdline_state; + TempArena scratch = BeginScratchNoConflict(); + { + StringList raw = GetRawCommandline(); + + u64 tmp_args_count = 0; + u64 tmp_positionals_count = 0; + CommandlineArg *tmp_args = PushStructs(scratch.arena, CommandlineArg, raw.count); + String *tmp_positionals = PushStructs(scratch.arena, String, raw.count); + { + String name = ZI; + for (StringListNode *n = raw.first; n; n = n->next) + { + String s = n->s; + if (StringBeginsWith(s, Lit("--"))) + { + if (name.len > 0) + { + CommandlineArg *arg = &tmp_args[tmp_args_count++]; + arg->name = name; + arg->exists = 1; + } + name = TrimLeft(s, Lit("--")); + } + else + { + if (name.len > 0) + { + CommandlineArg *arg = &tmp_args[tmp_args_count++]; + arg->name = name; + arg->value = s; + arg->exists = 1; + name = Zstr; + } + else + { + tmp_positionals[tmp_positionals_count++] = s; + } + } + } + if (name.len > 0) + { + CommandlineArg *arg = &tmp_args[tmp_args_count++]; + arg->name = name; + arg->exists = 1; + } + } + + Arena *perm = PermArena(); + g->positional_args_count = tmp_positionals_count; + g->positional_args = PushStructsNoZero(perm, String, tmp_positionals_count); + CopyStructs(g->positional_args, tmp_positionals, tmp_positionals_count); + for (u64 i = 0; i < tmp_args_count; ++i) + { + CommandlineArg arg = tmp_args[i]; + CommandlineArgNode *n = PushStruct(perm, CommandlineArgNode); + u64 hash = HashFnv64(Fnv64Basis, arg.name); + u64 bin_idx = hash % CommandlineArgBinsCount; + n->arg = arg; + n->hash = hash; + n->next = g->arg_bins[bin_idx]; + g->arg_bins[bin_idx] = n; + } + } + EndScratch(scratch); +} + +//////////////////////////////////////////////////////////// +//~ Command line operations + +String StringFromCommandlineIdx(i32 idx) +{ + SharedCmdlineState *g = &shared_cmdline_state; + String result = ZI; + if (idx < g->positional_args_count) + { + result = g->positional_args[idx]; + } + return result; +} + +CommandlineArg CommandlineArgFromName(String name) +{ + SharedCmdlineState *g = &shared_cmdline_state; + CommandlineArg result = ZI; + u64 hash = HashFnv64(Fnv64Basis, name); + for (CommandlineArgNode *n = g->arg_bins[hash % CommandlineArgBinsCount]; n; n = n->next) + { + if (n->hash == hash && EqString(n->arg.name, name)) + { + result = n->arg; + break; + } + } + return result; +} diff --git a/src/base/base_cmdline.h b/src/base/base_cmdline.h new file mode 100644 index 00000000..816d2c1f --- /dev/null +++ b/src/base/base_cmdline.h @@ -0,0 +1,42 @@ +//////////////////////////////////////////////////////////// +//~ Command line types + +Struct(CommandlineArg) +{ + b32 exists; + String name; + String value; +}; + +//////////////////////////////////////////////////////////// +//~ Lookup types + +Struct(CommandlineArgNode) +{ + CommandlineArgNode *next; + u64 hash; + CommandlineArg arg; +}; + +//////////////////////////////////////////////////////////// +//~ State types + +#define CommandlineArgBinsCount 1024 + +Struct(SharedCmdlineState) +{ + String *positional_args; + u64 positional_args_count; + CommandlineArgNode *arg_bins[CommandlineArgBinsCount]; +} extern shared_cmdline_state; + +//////////////////////////////////////////////////////////// +//~ Initialization + +void InitCmdline(void); + +//////////////////////////////////////////////////////////// +//~ Command line operations + +String StringFromCommandlineIdx(i32 idx); +CommandlineArg CommandlineArgFromName(String name); diff --git a/src/base/base_inc.h b/src/base/base_inc.h index 4a6047d5..3d0c3191 100644 --- a/src/base/base_inc.h +++ b/src/base/base_inc.h @@ -12,9 +12,10 @@ # include "base_snc.h" # include "base_job.h" # include "base_time.h" -# include "base_log.h" # include "base_uid.h" # include "base_string.h" +# include "base_cmdline.h" +# include "base_log.h" # include "base_uni.h" # include "base_gstat.h" # include "base_buddy.h" @@ -37,6 +38,7 @@ # include "base_snc.c" # include "base_uid.c" # include "base_string.c" +# include "base_cmdline.c" # include "base_uni.c" # include "base_gstat.c" # include "base_buddy.c" diff --git a/src/base/base_string.c b/src/base/base_string.c index bc3200c3..9be7cf2b 100644 --- a/src/base/base_string.c +++ b/src/base/base_string.c @@ -386,7 +386,7 @@ b32 StringContains(String str, String substring) return 0; } -b32 StringStartsWith(String str, String substring) +b32 StringBeginsWith(String str, String substring) { if (str.len >= substring.len) { @@ -464,7 +464,7 @@ String StringFromList(Arena *arena, StringList l, String separator) String TrimLeft(String s, String pattern) { String result = s; - while (StringStartsWith(result, pattern)) + while (StringBeginsWith(result, pattern)) { result.text += pattern.len; result.len -= pattern.len; @@ -492,7 +492,7 @@ String TrimWhitespace(String s) b32 stop = 0; while (!stop) { - if (StringStartsWith(s, Lit("\n")) || StringStartsWith(s, Lit("\r")) || StringStartsWith(s, Lit(" "))) + if (StringBeginsWith(s, Lit("\n")) || StringBeginsWith(s, Lit("\r")) || StringBeginsWith(s, Lit(" "))) { s.text += 1; s.len -= 1; diff --git a/src/base/base_string.h b/src/base/base_string.h index ee0d2eb7..37e14e5a 100644 --- a/src/base/base_string.h +++ b/src/base/base_string.h @@ -78,7 +78,7 @@ String IndentString(Arena *arena, String str, u32 indent); String LowerString(Arena *arena, String str); b32 EqString(String str1, String str2); b32 StringContains(String str, String substring); -b32 StringStartsWith(String str, String substring); +b32 StringBeginsWith(String str, String substring); b32 StringEndsWith(String str, String substring); //////////////////////////////////////////////////////////// diff --git a/src/base/base_win32/base_win32.c b/src/base/base_win32/base_win32.c index 2a453f8b..2ba471c6 100644 --- a/src/base/base_win32/base_win32.c +++ b/src/base/base_win32/base_win32.c @@ -9,7 +9,7 @@ BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name TempArena scratch = BeginScratchNoConflict(); String entry_name = StringFromWstrNoLimit(scratch.arena, (LPWSTR)wstr_entry_name); String embedded_data_prefix = Lit(Stringize(W32_EmbeddedDataPrefix)); - if (StringStartsWith(entry_name, embedded_data_prefix)) + if (StringBeginsWith(entry_name, embedded_data_prefix)) { HRSRC hres = FindResourceW(module, wstr_entry_name, type); if (hres) @@ -38,10 +38,9 @@ BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name //////////////////////////////////////////////////////////// //~ @hookdef Core hooks -StringList GetCommandLineArgs(void) +StringList GetRawCommandline(void) { - StringList result = ZI; - return result; + return W32_shared_state.raw_command_line; } void Echo(String msg) @@ -336,6 +335,27 @@ i32 W32_Main(void) /* Init futex system */ InitFutexSystem(); + /* Get raw args from command line */ + { + Arena *perm = PermArena(); + StringList args_list = ZI; + { + LPCWSTR cmdline_wstr = GetCommandLineW(); + i32 argc = 0; + LPWSTR *argv = CommandLineToArgvW(cmdline_wstr, &argc); + for (i32 i = 0; i < argc; ++i) + { + wchar_t *arg_wstr = argv[i]; + String arg = StringFromWstrNoLimit(perm, arg_wstr); + PushStringToList(perm, &args_list, arg); + } + } + g->raw_command_line = args_list; + } + + /* Init command line */ + InitCmdline(); + /* Init log system */ /* FIXME: Remove hardcoded log path */ InitLogSystem(Lit("log.log")); diff --git a/src/base/base_win32/base_win32.h b/src/base/base_win32/base_win32.h index 0a613856..be697980 100644 --- a/src/base/base_win32/base_win32.h +++ b/src/base/base_win32/base_win32.h @@ -34,6 +34,8 @@ Struct(W32_SharedState) i64 timer_start_qpc; i64 ns_per_qpc; + StringList raw_command_line; + //- Application control flow Atomic32 panicking; wchar_t panic_wstr[4096]; diff --git a/src/meta/meta.c b/src/meta/meta.c index 27d526f3..d898d185 100644 --- a/src/meta/meta.c +++ b/src/meta/meta.c @@ -63,6 +63,14 @@ //- Source files #include "meta_lay.c" +//////////////////////////////////////////////////////////// +//~ Global command line args + +Struct(CmdLineArgs) +{ + String leaf_layer_name; +} cmdline = ZI; + //////////////////////////////////////////////////////////// //~ Util @@ -216,7 +224,7 @@ JobDef(Step, sig, id) if (flags & StepParamsFlag_CompileProgram) { //- Generate C file - String c_out_file = F_GetFull(arena, Lit("pp_gen_c.c")); + String c_out_file = F_GetFull(arena, StringF(arena, "%F_gen_c.c", FmtString(cmdline.leaf_layer_name))); { StringList c_store_lines = ZI; StringList c_shader_lines = ZI; @@ -381,7 +389,7 @@ JobDef(Step, sig, id) } //- Compile C - String c_out_obj_file = Lit("pp_gen_c.obj"); + String c_out_obj_file = StringF(arena, "%F_gen_c.obj", FmtString(cmdline.leaf_layer_name)); PushStringToList(arena, &result->obj_files, c_out_obj_file); if (errors->count == 0) { @@ -426,7 +434,7 @@ JobDef(Step, sig, id) } //- Generate GPU file & shader entries - String gpu_out_file = F_GetFull(arena, Lit("pp_gen_gpu.gpu")); + String gpu_out_file = F_GetFull(arena, StringF(arena, "%F_gen_gpu.gpu", FmtString(cmdline.leaf_layer_name))); Enum(ShaderEntryKind) { ShaderEntryKind_VS, ShaderEntryKind_PS, ShaderEntryKind_CS, }; Struct(ShaderEntry) { ShaderEntry *next; ShaderEntryKind kind; String name; }; ShaderEntry *first_shader_entry = 0; @@ -875,16 +883,33 @@ JobDef(Build, _, __) } } + + ////////////////////////////// + //- Command line + + { + String layer_name = ZI; + CommandlineArg arg = CommandlineArgFromName(Lit("layer")); + if (arg.name.len != 0) + { + layer_name = arg.value; + } + else + { + layer_name = StringFromCommandlineIdx(1); + } + if (layer_name.len == 0) + { + EchoLine(Lit("No layer supplied, assuming \"pp\" build")); + layer_name = Lit("pp"); + } + EchoLine(StringF(arena, "Building program from layer \"%F\"", FmtString(layer_name))); + cmdline.leaf_layer_name = layer_name; + } + ////////////////////////////// //- Args - //- Unpack args - StringList args = GetCommandLineArgs(); - for (StringListNode *n = args.first; n; n = n->next) - { - String arg = n->s; - } - //- Generate compiler params CompilerParams cp = ZI; { @@ -994,7 +1019,7 @@ JobDef(Build, _, __) M_Layer flattened = ZI; { StringList starting_layer_names = ZI; - PushStringToList(arena, &starting_layer_names, Lit("pp")); + PushStringToList(arena, &starting_layer_names, cmdline.leaf_layer_name); flattened = M_GetFlattenedEntries(arena, parsed, starting_layer_names); } M_AppendErrors(arena, &errors, flattened.errors); @@ -1059,8 +1084,7 @@ JobDef(Build, _, __) } //- Link - - String exe_file = Lit("pp.exe"); + String exe_file = StringF(arena, "%F.exe", FmtString(cmdline.leaf_layer_name)); { /* Wait for exe to become writable (wait for program to close) */ f32 timeout = 1.0;