0

I used open3 of perl to run a command, the custom command behaves like a shell it takes input and displays output and waits for another input till quit is given

Now I've to use same command and write it in C language, do we have something similar to IPC::Open3 in C or C++ ?

learner
  • 9
  • 1
  • 1
    pipe() and fork() can do the same thing, but it's of course a lot more cumbersome. Start by reading [Safe Pipe Opens in perldoc perlipc](http://perldoc.perl.org/perlipc.html#Safe-Pipe-Opens) which is a comparatively high-level discussion of these concepts. You can then transfer the same concepts to Posix/C. – amon Jan 18 '18 at 08:37
  • Yes i was looking at pipe and fork but i'm unable to get it to work and its way beyond my understanding, i guess it takes some time to get over it – learner Jan 18 '18 at 09:15
  • In C or in C++? It's not the same. Windows or Linux? – zdim Jan 18 '18 at 09:30
  • In short: `system` is easiest but may be insecure (and doesn't give all that `Open3` does); `popen` is better, as well as `fork`+`exec`. I am not sure whether "IPC::Open3" indicates Linux only (don't know whether it's portable), but: on Windows there are API for this, [CreateProcess](https://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx) in the first place, and then `ShellExecute` (probably more) – zdim Jan 18 '18 at 09:53
  • If you can use `boost` then [`boost::process`](http://www.boost.org/doc/libs/1_66_0/doc/html/process.html) is probably worth a look. – G.M. Jan 18 '18 at 10:19
  • `open3` is just a series of system calls. It would be trivial to port to C. – ikegami Jan 18 '18 at 15:07
  • @learner: Please answer **zdim's** question about whether you are working on Windows or Linux (or something else). – Borodin Jan 18 '18 at 18:31
  • @Borodin : I'm on POSIX, RHEL to be precise – learner Jan 24 '18 at 04:59

1 Answers1

0

popen() supports one-way communications. If you want bidirectional data exchange, you'll need 2 pipes. Jeff Epler came up with the following bidirectional popen2.c implementation:

#include <sys/types.h>
#include <unistd.h>

struct popen2 {
    pid_t child_pid;
    int   from_child, to_child;
};

int popen2(const char *cmdline, struct popen2 *childinfo) {
    pid_t p;
    int pipe_stdin[2], pipe_stdout[2];

    if(pipe(pipe_stdin)) return -1;
    if(pipe(pipe_stdout)) return -1;

    printf("pipe_stdin[0] = %d, pipe_stdin[1] = %d\n", pipe_stdin[0], pipe_stdin[1]);
    printf("pipe_stdout[0] = %d, pipe_stdout[1] = %d\n", pipe_stdout[0], pipe_stdout[1]);

    p = fork();
    if(p < 0) return p; /* Fork failed */
    if(p == 0) { /* child */
        close(pipe_stdin[1]);
        dup2(pipe_stdin[0], 0);
        close(pipe_stdout[0]);
        dup2(pipe_stdout[1], 1);
        execl("/bin/sh", "sh", "-c", cmdline, 0);
        perror("execl"); exit(99);
    }
    childinfo->child_pid = p;
    childinfo->to_child = pipe_stdin[1];
    childinfo->from_child = pipe_stdout[0];
    return 0; 
}

#define TESTING
#ifdef TESTING
int main(void) {
    char buf[1000];
    struct popen2 kid;
    popen2("tr a-z A-Z", &kid);
    write(kid.to_child, "testing\n", 8);
    close(kid.to_child);
    memset(buf, 0, 1000);
    read(kid.from_child, buf, 1000);
    printf("kill(%d, 0) -> %d\n", kid.child_pid, kill(kid.child_pid, 0)); 
    printf("from child: %s", buf); 
    printf("waitpid() -> %d\n", waitpid(kid.child_pid, NULL, 0));
    printf("kill(%d, 0) -> %d\n", kid.child_pid, kill(kid.child_pid, 0)); 
    return 0;
}
#endif
Laszlo
  • 769
  • 9
  • 19
  • While these links may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – Gerhard Jan 18 '18 at 08:50
  • 1
    Gerhard Barnard, what is your point? "Try popen()" is the essential part. :) Also, I am afraid popen() specs will not change significantly any time soon, and I don't believe those links will become dead soon. At least until 'learner' gets a chance to click on them. Anyway, I hope the examples included will not trigger more stereotype reactions. – Laszlo Jan 18 '18 at 09:42
  • thanks for the heads up but i already know this, what i was looking for can be thought as bidirectional communication, like popen2 gives input and output file descriptors? I guess there is nothing like this in C or CPP – learner Jan 18 '18 at 10:04
  • @Laszlo, We work on review, which is based on SO terms and Conditions, we do not post link only answers and the post was originally marked as low quality because of the link only answer. If you subsequently received 4 delete votes, it would have been deleted, hence why the comment was posted. After edit, it should be fine. – Gerhard Jan 18 '18 at 11:19
  • @learner, yes, you will need to use 2 pipes, as they are unidirectional. – Laszlo Jan 18 '18 at 11:22
  • @learner I found some popen2 implementations here at stackoverflow ( https://stackoverflow.com/questions/12778672/killing-process-that-has-been-created-with-popen2 ), and one here: https://media.unpythonic.net/emergent-files/01108826729/popen2.c . Does it help? – Laszlo Jan 18 '18 at 11:33