Created
October 21, 2021 19:26
-
-
Save fmitha/44781cbe8a9c655a0d67f3c511405a1e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* -- https://chat.stackexchange.com/transcript/message/59383566#59383566 */ | |
/* -- You may use tput. Examples: tput >/dev/null (status == 2, usage */ | |
/* -- error), TERM=foo tput >/dev/null (status == 3, no information for */ | |
/* -- the terminal type), tput foo >/dev/null (status == 4, unknown */ | |
/* -- capability). It can also return 1, which POSIX says is */ | |
/* -- "unspecified" and historically used to tell the terminal doesn't */ | |
/* -- have the specified capability (e.g. TERM=vt100 tput setaf */ | |
/* -- >/dev/null); notably, in this case the exit status is ≠ 0, but no */ | |
/* -- error message is printed out. */ | |
/* local posix = require "posix" */ | |
/* -- Thread at https://stackoverflow.com/q/1242572/350713 */ | |
/* require("posix") */ | |
/* -- */ | |
/* -- Simple popen3() implementation */ | |
/* -- */ | |
/* function popen3(path, ...) */ | |
/* local r1, w1 = posix.pipe() */ | |
/* local r2, w2 = posix.pipe() */ | |
/* local r3, w3 = posix.pipe() */ | |
/* assert((r1 ~= nil or r2 ~= nil or r3 ~= nil), "pipe() failed") */ | |
/* local pid, err = posix.fork() */ | |
/* assert(pid ~= nil, "fork() failed") */ | |
/* if pid == 0 then -- child */ | |
/* posix.close(w1) */ | |
/* posix.close(r2) */ | |
/* posix.dup2(r1, posix.fileno(io.stdin)) */ | |
/* posix.dup2(w2, posix.fileno(io.stdout)) */ | |
/* posix.dup2(w3, posix.fileno(io.stderr)) */ | |
/* posix.close(r1) */ | |
/* posix.close(w2) */ | |
/* posix.close(w3) */ | |
/* local ret, err = posix.execp(path, unpack({...})) */ | |
/* assert(ret ~= nil, "execp() failed") */ | |
/* posix._exit(1) */ | |
/* return */ | |
/* end */ | |
/* posix.close(r1) */ | |
/* posix.close(w2) */ | |
/* posix.close(w3) */ | |
/* return pid, w1, r2, r3 */ | |
/* end */ | |
/* popen3("/bin/lsx -la") */ | |
/* --[[ */ | |
/* -- */ | |
/* -- Pipe input into cmd + optional arguments and wait for completion */ | |
/* -- and then return status code, stdout and stderr from cmd. */ | |
/* -- */ | |
/* function pipe_simple(input, cmd, ...) */ | |
/* -- */ | |
/* -- Launch child process */ | |
/* -- */ | |
/* local pid, w, r, e = popen3(cmd, unpack({...})) */ | |
/* assert(pid ~= nil, "filter() unable to popen3()") */ | |
/* -- */ | |
/* -- Write to popen3's stdin, important to close it as some (most?) proccess */ | |
/* -- block until the stdin pipe is closed */ | |
/* -- */ | |
/* posix.write(w, input) */ | |
/* posix.close(w) */ | |
/* local bufsize = 4096 */ | |
/* -- */ | |
/* -- Read popen3's stdout via Posix file handle */ | |
/* -- */ | |
/* local stdout = {} */ | |
/* local i = 1 */ | |
/* while true do */ | |
/* buf = posix.read(r, bufsize) */ | |
/* if buf == nil or #buf == 0 then break end */ | |
/* stdout[i] = buf */ | |
/* i = i + 1 */ | |
/* end */ | |
/* -- */ | |
/* -- Read popen3's stderr via Posix file handle */ | |
/* -- */ | |
/* local stderr = {} */ | |
/* local i = 1 */ | |
/* while true do */ | |
/* buf = posix.read(e, bufsize) */ | |
/* if buf == nil or #buf == 0 then break end */ | |
/* stderr[i] = buf */ | |
/* i = i + 1 */ | |
/* end */ | |
/* -- */ | |
/* -- Clean-up child (no zombies) and get return status */ | |
/* -- */ | |
/* local wait_pid, wait_cause, wait_status = posix.wait(pid) */ | |
/* return wait_status, table.concat(stdout), table.concat(stderr) */ | |
/* end */ | |
/* -- */ | |
/* -- Example usage */ | |
/* -- */ | |
/* local my_in = io.stdin:read("*all") */ | |
/* --local my_cmd = "wc" */ | |
/* --local my_args = {"-l"} */ | |
/* local my_cmd = "spamc" */ | |
/* local my_args = {} -- no arguments */ | |
/* local my_status, my_out, my_err = pipe_simple(my_in, my_cmd, unpack(my_args)) */ | |
/* -- Obviously not interleaved as they would have been if printed in realtime */ | |
/* io.stdout:write(my_out) */ | |
/* io.stderr:write(my_err) */ | |
/* os.exit(my_status) */ | |
/* --]] */ | |
#include <assert.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <sys/types.h> | |
#include <sys/wait.h> | |
#include <fcntl.h> | |
void popen3(void) | |
{ | |
/* local r1, w1 = posix.pipe(); */ | |
/* local r2, w2 = posix.pipe(); */ | |
/* local r3, w3 = posix.pipe(); */ | |
int fda[2], fdb[2], fdc[2]; | |
/* pipe(fd1); */ | |
/* pipe(fd2); */ | |
/* pipe(fd3); */ | |
// Returns: 0 if OK, −1 on error | |
assert((pipe(fda) == 0) && (pipe(fdb) == 0) && (pipe(fdc) == 0)); | |
int r1 = fda[0]; int w1 = fda[1]; | |
int r2 = fdb[0]; int w2 = fdb[1]; | |
int r3 = fdc[0]; int w3 = fdc[1]; | |
/* assert((r1 ~= nil or r2 ~= nil or r3 ~= nil), "pipe() failed") */ | |
// assert((pipe(fd1) < 0) || (pipe(fd2) < 0) || (pipe(fd3) < 0)); | |
// assert((pipe(fd1) > 0)); | |
// assert((pipe(fd1) == 0)); | |
/* local pid, err = posix.fork() */ | |
/* assert(pid ~= nil, "fork() failed") */ | |
//pid_t parent = getpid(); | |
pid_t pid = fork(); | |
if (pid == -1) // fork failed | |
{ | |
; // error, failed to fork() | |
} | |
else if (pid > 0) // parent process | |
{ | |
int status; | |
waitpid(pid, &status, 0); | |
if(WIFEXITED(status)) | |
printf("Child's exit code is %d\n", WEXITSTATUS(status)); | |
else | |
printf("Child did not terminate with exit\n"); | |
} | |
else // | |
{ | |
/* posix.close(w1) */ | |
/* posix.close(r2) */ | |
/* posix.dup2(r1, posix.fileno(io.stdin)) */ | |
/* posix.dup2(w2, posix.fileno(io.stdout)) */ | |
/* posix.dup2(w3, posix.fileno(io.stderr)) */ | |
/* posix.close(r1) */ | |
/* posix.close(w2) */ | |
/* posix.close(w3) */ | |
close(w1); | |
close(r2); | |
close(r3); | |
// stdin, stdout, stderr defined in "5.3 Standard Input, | |
// Standard Output, and Standard Error" | |
dup2(r1, fileno(stdin)); | |
dup2(w2, fileno(stdout)); | |
dup2(w3, fileno(stderr)); | |
close(r1); | |
close(w2); | |
close(w3); | |
/* local ret, err = posix.execp(path, unpack({...})) */ | |
/* assert(ret ~= nil, "execp() failed") */ | |
//int ret, err = execlp(path, unpack({...})) */ | |
execlp("lsx", "lsx", "-la", "zarko.tex", (char *)NULL); | |
_exit(EXIT_FAILURE); // exec never returns | |
} | |
/* posix._exit(1) */ | |
/* return */ | |
/* end */ | |
} | |
int main(void) | |
{ | |
popen3(); | |
return(0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment