diff --git a/example/commands.c b/example/commands.c new file mode 100644 index 0000000..83ecf32 --- /dev/null +++ b/example/commands.c @@ -0,0 +1,26 @@ +#include +#define GEBS_IMPLEMENTATION +#include "../gebs.h" + +int main(int argc, char ** argv) +{ + gebs_rebuild_self(argc, argv, "cc", "-o", "commands", __FILE__); + + int code = GEBS_CMD("ls", "-la"); + GEBS_LOGI("Exited with %d\n", code); + + Gebs_Cmd cmd = {0}; + defer { gebs_list_free(&cmd); } + gebs_cmd_append(&cmd, "ls"); + gebs_cmd_append(&cmd, "-la"); + + + Gebs_String_Builder out_sb = {0}; + defer { gebs_sb_free(&out_sb); } + code = gebs_cmd_run_collect(&cmd, &out_sb); + printf("CAPTURED\n%sCAPTURED\n", out_sb.items); + + GEBS_LOGI("Exited with %d\n", code); + + return 0; +} diff --git a/gebs.c b/gebs.c index 36c476d..56663c3 100644 --- a/gebs.c +++ b/gebs.c @@ -17,6 +17,11 @@ int main(int argc, char ** argv) if (GEBS_CMD("gcc", "-ggdb", "-o", "build/arena", "example/arena.c") != 0) return 1; } + if (gebs_needs_rebuild_many("build/commands", "example/commands.c", "gebs.h")) { + if (GEBS_CMD("gcc", "-ggdb", "-o", "build/commands", "example/commands.c") != 0) { + return 1; + } + } return 0; } diff --git a/gebs.h b/gebs.h index e52fad4..59099ef 100644 --- a/gebs.h +++ b/gebs.h @@ -236,6 +236,14 @@ int gebs_cmd_run_sync_alloc(Gebs_Allocator *alloc, Gebs_Cmd *cmd); gebs_cmd_run(&__cmd); \ }) +int gebs_cmd_run_sync_collect_alloc(Gebs_Allocator *alloc, + Gebs_Cmd *cmd, Gebs_String_Builder *sb_out); + +#define gebs_cmd_run_collect_alloc gebs_cmd_run_sync_collect_alloc + +#define gebs_cmd_run_collect(cmd, out) \ + gebs_cmd_run_collect_alloc(&gebs_default_allocator, (cmd), (out)) + // ---------------------------------------------------------------------------- // The build system // ---------------------------------------------------------------------------- @@ -330,6 +338,69 @@ int gebs_cmd_run_sync_alloc(Gebs_Allocator *alloc, Gebs_Cmd *cmd) #endif } +int gebs_cmd_run_sync_collect_alloc(Gebs_Allocator *alloc, Gebs_Cmd *cmd, Gebs_String_Builder *sb_out) +{ + Gebs_String_Builder sb = {0}; + gebs_nsl_join_alloc(alloc, cmd, &sb, " "); + GEBS_LOGI("cmd `%s`\n", sb.items); + +#if GEBS_PLATFORM == GEBS_PLATFORM_POSIX + // Clone the list + Gebs_Cmd new_cmd = {0}; + defer { gebs_cmd_free_alloc(alloc, &new_cmd); } + for (size_t i = 0; i < cmd->count; i++) { + gebs_cmd_append_alloc(alloc, &new_cmd, cmd->items[i]); + } + gebs_cmd_append_alloc((alloc), &new_cmd, NULL); + + int pipe_ends[2]; + pipe(pipe_ends); + + pid_t pid = vfork(); + switch (pid) { + case -1: + close(pipe_ends[0]); + close(pipe_ends[1]); + GEBS_LOGE("Could not vfork\n"); + return -1; + case 0: + close(pipe_ends[0]); + dup2(pipe_ends[1], 1); + close(pipe_ends[1]); + + execvp(new_cmd.items[0], (char * const *)new_cmd.items); + exit(EXIT_FAILURE); + default: { + close(pipe_ends[1]); + char c; + while (read(pipe_ends[0], &c, 1) > 0) { + gebs_sb_append_char_alloc(alloc, sb_out, c); + } + gebs_sb_finish_alloc(alloc, sb_out); + + int wstatus; + do { + if (waitpid(pid, &wstatus, WUNTRACED | WCONTINUED) == -1) { + return -1; + } + + if (WIFEXITED(wstatus)) { + return WEXITSTATUS(wstatus); + } else if (WIFSIGNALED(wstatus)) { + GEBS_LOGI("%d killed by %d\n", pid, WTERMSIG(wstatus)); + return -1; + } else if (WIFSTOPPED(wstatus)) { + GEBS_LOGI("%d stopped by %d\n", pid, WSTOPSIG(wstatus)); + return -1; + } + } while(!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus)); + } + } +#else +# error "gebs_cmd_run_sync_alloc unknown command" +#endif +} + // ---------------------------------------------------------------------------- // Allocators // ----------------------------------------------------------------------------