/* popen2.h - include file for popen2
**
** Partly derived from:
** http://media.unpythonic.net/emergent-files/01108826729/popen2.c
** https://raw.githubusercontent.com/vi/syscall_limiter/master/writelimiter/popen2.c
**
** Regular popen opens a single pipe. Pipes are inherently uni-directional,
** so even though popen accepts a "r+" mode flag, it doesn't work for
** writing to and reading from the same command.
**
** Popen2 opens two separate pipes, one for writing the command's input
** and one for reading the command's output. The file descriptors are
** returned in a phandle2 object.
**
** As with regular popen, there's a pclose2 routine to close the pipes.
**
** There's also a new pwriteread2 routine that abstracts interleaved
** writing and reading via select(2), to avoid deadlocks. If the input
** you're sending is guaranteed small, you can go ahead and just write
** it directly and then read the results. For large input you need to
** use select(2) or the equivalent, and this new routine makes that easier.
*/

#ifndef _POPEN2_H_
#define _POPEN2_H_

typedef struct
    {
    pid_t child_pid;
    int to_child, from_child;
    } phandle2;

/* Create a bi-directional command pipe. */
int popen2( const char* cmd, phandle2* handle );

/* Write to or read from the command pipe. (Client data is an uninterpreted
** pointer that just gets passed through. It's how you send data to callbacks
** in languages that don't have nested functions or closures.)
*/
typedef int (pwriteread_cb)( phandle2* handle, void* client_data );
int pwriteread2( phandle2* handle, pwriteread_cb write_cb, void* write_cd, pwriteread_cb read_cb, void* read_cd );

/* Close the command pipe. */
int pclose2( phandle2* handle );

#endif /* _POPEN2_H_ */
