#include "commander.h" #include "commander_output.h" #include "../utils/shell_utils.h" #include "../../../mem/allocator/mem_allocator.h" #include "../../../mem/arena/mem_arena_allocator.h" #include "../../../strings/str8/str8.h" #include "../../../../common/aliases/aliases.h" #include "../../../../common/misc/misc_utils.h" #include #include #include #include #include #define CMD_BUF_LEN 8192 #define OUT_BUF_LEN 4096 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 wapp_shell_commander_execute(CMDOutHandling out_handling, Str8 *out_buf, const Str8List *cmd) { if (!cmd) { return CMD_NO_EXIT(SHELL_ERR_INVALID_ARGS); } Allocator arena = wapp_mem_arena_allocator_init(KB(500)); 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); } // Redirect output cmd_str = wapp_str8_alloc_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(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); if (err > SHELL_ERR_NO_ERROR) { output = CMD_NO_EXIT(err); goto EXECUTE_COMMAND_CLOSE; } i32 st = EXIT_SUCCESS; err = get_output_status(fp, &st); if (err > SHELL_ERR_NO_ERROR) { output = CMD_NO_EXIT(err); goto EXECUTE_COMMAND_CLOSE; } // Process is already closed in get_output_status fp = NULL; output = (CMDResult){ .exited = true, .exit_code = st, .error = SHELL_ERR_NO_ERROR, }; EXECUTE_COMMAND_CLOSE: if (fp) { wapp_shell_utils_pclose(fp); } return output; } internal inline CMDError get_command_output(FILE *fp, CMDOutHandling out_handling, Str8 *out_buf) { Str8 out = wapp_str8_buf(OUT_BUF_LEN); 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; }