diff --git a/src/os/shell/commander/commander.c b/src/os/shell/commander/commander.c index 9ad69b5..f49e7e3 100644 --- a/src/os/shell/commander/commander.c +++ b/src/os/shell/commander/commander.c @@ -1,6 +1,11 @@ #include "commander.h" #include "aliases.h" +#include "commander_output.h" +#include "mem_allocator.h" +#include "mem_arena_allocator.h" +#include "misc_utils.h" #include "shell_utils.h" +#include "str8.h" #include #include #include @@ -10,62 +15,44 @@ #define CMD_BUF_LEN 8192 #define OUT_BUF_LEN 4096 -internal inline CMDError build_command_from_args(char *cmd, u64 buf_len, va_list args); -internal inline CMDResult execute_command(const char *cmd, CMDOutHandling out_handling, char *out_buf, - u64 buf_size); -internal inline CMDError get_command_output(FILE *fp, CMDOutHandling out_handling, char *out_buf, - u64 buf_size); +internal inline CMDResult execute_command(Str8RO *cmd, CMDOutHandling out_handling, Str8 *out_buf); +internal inline CMDError get_command_output(FILE *fp, CMDOutHandling out_handling, Str8 *out_buf); -CMDResult run_command(CMDOutHandling out_handling, char *out_buf, u64 buf_size, ...) { - va_list args; - va_start(args, buf_size); - - char cmd[CMD_BUF_LEN] = {0}; - CMDError err = build_command_from_args(cmd, CMD_BUF_LEN, args); - if (err > SHELL_ERR_NO_ERROR) { - va_end(args); - return CMD_NO_EXIT(err); +CMDResult wapp_shell_commander_execute(CMDOutHandling out_handling, Str8 *out_buf, const Str8List *cmd) { + if (!cmd) { + return CMD_NO_EXIT(SHELL_ERR_INVALID_ARGS); } - va_end(args); + Allocator arena = wapp_mem_arena_allocator_init(MB(100)); - return execute_command(cmd, out_handling, out_buf, buf_size); -} - -internal inline CMDError build_command_from_args(char *cmd, u64 buf_len, - va_list args) { - u64 size = 0; - u64 arg_len = 0; - - const char *arg = va_arg(args, const char *); - while (arg) { - arg_len = strlen(arg); - if (arg_len >= buf_len - size) { - return SHELL_ERR_CMD_BUF_FULL; - } - - strcat(cmd, arg); - cmd[size + arg_len] = ' '; - - size += arg_len + 1; - - arg = va_arg(args, const char *); + Str8 *cmd_str = wapp_str8_join(&arena, cmd, &wapp_str8_lit_ro(" ")); + if (!cmd_str) { + wapp_mem_arena_allocator_destroy(&arena); + return CMD_NO_EXIT(SHELL_ERR_ALLOCATION_FAIL); } - return SHELL_ERR_NO_ERROR; + // Redirect output + cmd_str = wapp_str8_concat(&arena, cmd_str, &wapp_str8_lit_ro(" 2>&1")); + + CMDResult output = execute_command(cmd_str, out_handling, out_buf); + + wapp_mem_arena_allocator_destroy(&arena); + + return output; } -internal inline CMDResult execute_command(const char *cmd, - CMDOutHandling out_handling, - char *out_buf, u64 buf_size) { - FILE *fp = wapp_shell_utils_popen(cmd, "r"); +internal inline CMDResult execute_command(Str8RO *cmd, CMDOutHandling out_handling, Str8 *out_buf) { + char cmd_buf[CMD_BUF_LEN] = {0}; + wapp_str8_copy_to_cstr(cmd_buf, cmd, CMD_BUF_LEN); + + FILE *fp = wapp_shell_utils_popen(cmd_buf, "r"); if (!fp) { return CMD_NO_EXIT(SHELL_ERR_PROC_START_FAIL); } CMDResult output; - CMDError err = get_command_output(fp, out_handling, out_buf, buf_size); + CMDError err = get_command_output(fp, out_handling, out_buf); if (err > SHELL_ERR_NO_ERROR) { output = CMD_NO_EXIT(err); goto EXECUTE_COMMAND_CLOSE; @@ -94,24 +81,18 @@ EXECUTE_COMMAND_CLOSE: return output; } -internal inline CMDError get_command_output(FILE *fp, - CMDOutHandling out_handling, - char *out_buf, u64 buf_size) { - char out[OUT_BUF_LEN] = {0}; - u64 max_out_length = OUT_BUF_LEN - 1; +internal inline CMDError get_command_output(FILE *fp, CMDOutHandling out_handling, Str8 *out_buf) { + Str8 out = wapp_str8_buf(OUT_BUF_LEN); - u64 buf_filled = 0; - while (fgets(out, (i32)max_out_length, fp)) { - if (out_handling == SHELL_OUTPUT_CAPTURE && out_buf != NULL) { - buf_filled += strlen(out); - if (buf_filled >= buf_size) { - return SHELL_ERR_OUT_BUF_FULL; - } - - strcat(out_buf, out); - } else if (out_handling == SHELL_OUTPUT_PRINT) { - printf("%s", out); + out.size = fread((void *)out.buf, sizeof(u8), out.capacity, fp); + if (out_handling == SHELL_OUTPUT_CAPTURE && out_buf != NULL) { + if (out.size >= out_buf->capacity) { + return SHELL_ERR_OUT_BUF_FULL; } + + wapp_str8_concat_capped(out_buf, &out); + } else if (out_handling == SHELL_OUTPUT_PRINT) { + printf(WAPP_STR8_SPEC, wapp_str8_varg(out)); } return SHELL_ERR_NO_ERROR; diff --git a/src/os/shell/commander/commander.h b/src/os/shell/commander/commander.h index 31c686d..8b63d2a 100644 --- a/src/os/shell/commander/commander.h +++ b/src/os/shell/commander/commander.h @@ -3,6 +3,7 @@ #include "aliases.h" #include "commander_output.h" +#include "str8.h" #include #include #include @@ -12,10 +13,8 @@ BEGIN_C_LINKAGE #endif // __cplusplus #define CMD_NO_EXIT(ERR) ((CMDResult){.exited = false, .exit_code = EXIT_FAILURE, .error = ERR}) -#define wapp_shell_commander_execute(HANDLE_OUTPUT, OUT_BUF, BUF_SIZE, ...) \ - run_command(HANDLE_OUTPUT, OUT_BUF, BUF_SIZE, __VA_ARGS__, "2>&1", NULL) -CMDResult run_command(CMDOutHandling out_handling, char *out_buf, u64 buf_size, ...); +CMDResult wapp_shell_commander_execute(CMDOutHandling out_handling, Str8 *out_buf, const Str8List *cmd); external CMDError get_output_status(FILE *fp, i32 *status_out); diff --git a/src/os/shell/commander/commander_output.h b/src/os/shell/commander/commander_output.h index 91eff5e..65ba08a 100644 --- a/src/os/shell/commander/commander_output.h +++ b/src/os/shell/commander/commander_output.h @@ -17,7 +17,8 @@ typedef enum { typedef enum { SHELL_ERR_NO_ERROR, - SHELL_ERR_CMD_BUF_FULL, + SHELL_ERR_INVALID_ARGS, + SHELL_ERR_ALLOCATION_FAIL, SHELL_ERR_PROC_START_FAIL, SHELL_ERR_OUT_BUF_FULL, SHELL_ERR_PROC_EXIT_FAIL, diff --git a/tests/shell_commander/test_shell_commander.c b/tests/shell_commander/test_shell_commander.c index 84e4060..569121f 100644 --- a/tests/shell_commander/test_shell_commander.c +++ b/tests/shell_commander/test_shell_commander.c @@ -1,5 +1,6 @@ #include "test_shell_commander.h" #include "commander.h" +#include "str8.h" #include "tester.h" #include #include @@ -7,7 +8,11 @@ #include TestFuncResult test_commander_cmd_success(void) { - CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_DISCARD, NULL, 0, "echo", "hello world"); + Str8List cmd = {0}; + wapp_str8_list_push_back(&cmd, &wapp_str8_node_from_cstr("echo")); + wapp_str8_list_push_back(&cmd, &wapp_str8_node_from_cstr("hello world")); + + CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_DISCARD, NULL, &cmd); bool succeeded = result.exited && result.exit_code == EXIT_SUCCESS && result.error == SHELL_ERR_NO_ERROR; @@ -15,7 +20,10 @@ TestFuncResult test_commander_cmd_success(void) { } TestFuncResult test_commander_cmd_failure(void) { - CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_DISCARD, NULL, 0, "grep"); + Str8List cmd = {0}; + wapp_str8_list_push_back(&cmd, &wapp_str8_node_from_cstr("grep")); + + CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_DISCARD, NULL, &cmd); bool failed = result.exited && result.exit_code != EXIT_SUCCESS && result.error == SHELL_ERR_NO_ERROR; @@ -23,27 +31,36 @@ TestFuncResult test_commander_cmd_failure(void) { } TestFuncResult test_commander_cmd_out_buf_success(void) { - char buf[64] = {0}; - char expected_output[64] = {0}; - const char *msg = "hello world"; - u64 length = strlen(msg); - snprintf(expected_output, length + 2, "%s\n", msg); + Str8 buf = wapp_str8_buf(64); + Str8 expected = wapp_str8_buf(64); + char msg[] = "hello world"; + wapp_str8_copy_cstr_capped(&expected, msg); + wapp_str8_concat_capped(&expected, &wapp_str8_lit_ro("\n")); - CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_CAPTURE, buf, 64, "echo", msg); + Str8List cmd = {0}; + wapp_str8_list_push_back(&cmd, &wapp_str8_node_from_cstr("echo")); + wapp_str8_list_push_back(&cmd, &wapp_str8_node_from_cstr(msg)); + + CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_CAPTURE, &buf, &cmd); bool succeeded = result.exited && result.exit_code == EXIT_SUCCESS && - result.error == SHELL_ERR_NO_ERROR && - strncmp(buf, expected_output, length) == 0; + result.error == SHELL_ERR_NO_ERROR && wapp_str8_equal(&buf, &expected); return wapp_tester_result(succeeded); } TestFuncResult test_commander_cmd_out_buf_failure(void) { - char buf[4] = {0}; - const char *msg = "hello world"; - u64 length = strlen(msg); - CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_CAPTURE, buf, 4, "echo", msg); + Str8 buf = wapp_str8_buf(4); + Str8 expected = wapp_str8_buf(64); + char msg[] = "hello world"; + wapp_str8_copy_cstr_capped(&expected, msg); + + Str8List cmd = {0}; + wapp_str8_list_push_back(&cmd, &wapp_str8_node_from_cstr("echo")); + wapp_str8_list_push_back(&cmd, &wapp_str8_node_from_cstr(msg)); + + CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_CAPTURE, &buf, &cmd); bool failed = !result.exited && result.exit_code != EXIT_SUCCESS && - result.error == SHELL_ERR_OUT_BUF_FULL && strncmp(buf, msg, length) != 0; + result.error == SHELL_ERR_OUT_BUF_FULL && !wapp_str8_equal(&buf, &expected); return wapp_tester_result(failed); }