// vim:fileencoding=utf-8:foldmethod=marker #include "commander.h" #include "commander_output.h" #include "../utils/shell_utils.h" #include "../../allocators/arena/mem_arena_allocator.h" #include "../../../common/aliases/aliases.h" #include "../../../common/misc/misc_utils.h" #include "../../../base/dbl_list/dbl_list.h" #include "../../../base/mem/allocator/mem_allocator.h" #include "../../../base/strings/str8/str8.h" #include #include #include #include #define CMD_BUF_LEN 8192 #define OUT_BUF_LEN 4096 wp_intern WpCmdResult executeCommand(WpStr8RO *cmd, WpCmdOutHandling out_handling, WpStr8 *out_buf); wp_intern WpCmdError getCommandOutput(FILE *fp, WpCmdOutHandling out_handling, WpStr8 *out_buf); WpCmdResult wpShellCommanderExecute(WpCmdOutHandling out_handling, WpStr8 *out_buf, const WpStr8List *cmd) { if (!cmd) { return wpCmdNoExit(WP_SHELL_ERR_INVALID_ARGS); } WpAllocator arena = wpMemArenaAllocatorInit(KiB(500)); WpStr8 *cmd_str = wpStr8Join(&arena, cmd, &wpStr8LitRo(" ")); if (!cmd_str) { wpMemArenaAllocatorDestroy(&arena); return wpCmdNoExit(WP_SHELL_ERR_ALLOCATION_FAIL); } // Redirect output cmd_str = wpStr8AllocConcat(&arena, cmd_str, &wpStr8LitRo(" 2>&1")); WpCmdResult output = executeCommand(cmd_str, out_handling, out_buf); wpMemArenaAllocatorDestroy(&arena); return output; } wp_intern WpCmdResult executeCommand(WpStr8RO *cmd, WpCmdOutHandling out_handling, WpStr8 *out_buf) { char cmd_buf[CMD_BUF_LEN] = {0}; wpStr8CopyToCstr(cmd_buf, cmd, CMD_BUF_LEN); FILE *fp = wpShellUtilsPopen(cmd_buf, "r"); if (!fp) { return wpCmdNoExit(WP_SHELL_ERR_PROC_START_FAIL); } WpCmdResult output; WpCmdError err = getCommandOutput(fp, out_handling, out_buf); if (err > WP_SHELL_ERR_NO_ERROR) { output = wpCmdNoExit(err); goto executeCommand_CLOSE; } i32 st = EXIT_SUCCESS; err = _getOutputStatus(fp, &st); if (err > WP_SHELL_ERR_NO_ERROR) { output = wpCmdNoExit(err); goto executeCommand_CLOSE; } // Process is already closed in _getOutputStatus fp = NULL; output = (WpCmdResult){ .exited = true, .exit_code = st, .error = WP_SHELL_ERR_NO_ERROR, }; executeCommand_CLOSE: if (fp) { wpShellUtilsPclose(fp); } return output; } wp_intern WpCmdError getCommandOutput(FILE *fp, WpCmdOutHandling out_handling, WpStr8 *out_buf) { WpStr8 out = wpStr8Buf(OUT_BUF_LEN); out.size = fread((void *)out.buf, sizeof(c8), out.capacity, fp); if (out_handling == WP_SHELL_OUTPUT_CAPTURE && out_buf != NULL) { if (out.size >= out_buf->capacity) { return WP_SHELL_ERR_OUT_BUF_FULL; } wpStr8ConcatCapped(out_buf, &out); } else if (out_handling == WP_SHELL_OUTPUT_PRINT) { printf(WP_STR8_SPEC, wpStr8Varg(out)); } return WP_SHELL_ERR_NO_ERROR; }