Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fds accessor #2

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions pstream.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ namespace redi
fopen(FILE*& in, FILE*& out, FILE*& err);
#endif

/// Obtain file descriptors for each of the process' standards streams.
std::size_t
fds(fd_type& in, fd_type& out, fd_type& err);

/// Return the exit status of the process.
int
status() const;
Expand Down Expand Up @@ -359,6 +363,10 @@ namespace redi
fopen(FILE*& in, FILE*& out, FILE*& err);
#endif

/// Obtain file descriptors for each of the process' standards streams.
std::size_t
fds(fd_type& in, fd_type& out, fd_type& err);

protected:
std::string command_; ///< The command used to start the process.
streambuf_type buf_; ///< The stream buffer.
Expand Down Expand Up @@ -2440,6 +2448,63 @@ namespace redi

#endif // REDI_EVISCERATE_PSTREAMS

/**
* @warning This function exposes the internals of the stream buffer and
* should be used with caution. It is the caller's responsibility
* to manage any interactions between iostream and raw I/O on the
* file descriptors.
*
* @param in An integer that will be the process' stdin.
* @param out An integer that will be the process' stdout.
* @param err An integer that will be the process' stderr.
* @return An OR of zero or more of @c pstdin, @c pstdout, @c pstderr.
*
* For each open stream shared with the child process the file descriptor
* used is assigned to the corresponding parameter. For closed
* streams @c -1 is assigned to the parameter.
* The return value can be tested to see which parameters are valid
* by masking with the corresponding @c pmode value.
*/
template <typename C, typename T>
std::size_t
basic_pstreambuf<C,T>::fds(fd_type& in, fd_type& out, fd_type& err)
{
in = out = err = -1;
std::size_t open_files = 0;
if (wpipe() > -1)
{
in = wpipe();
open_files |= pstdin;
}
if (rpipe(rsrc_out) > -1)
{
out = rpipe(rsrc_out);
open_files |= pstdout;
}
if (rpipe(rsrc_err) > -1)
{
err = rpipe(rsrc_err);
open_files |= pstderr;
}
return open_files;
}

/**
* @warning This function exposes the internals of the stream buffer and
* should be used with caution.
*
* @param in An integer that will refer to the process' stdin.
* @param out An integer that will refer to the process' stdout.
* @param err An integer that will refer to the process' stderr.
* @return A bitwise-or of zero or more of @c pstdin, @c pstdout, @c pstderr.
* @see basic_pstreambuf::fds()
*/
template <typename C, typename T>
inline std::size_t
pstream_common<C,T>::fds(fd_type& fin, fd_type& fout, fd_type& ferr)
{
return buf_.fds(fin, fout, ferr);
}

} // namespace redi

Expand Down
79 changes: 79 additions & 0 deletions test_pstreams.cc
Original file line number Diff line number Diff line change
Expand Up @@ -705,10 +705,12 @@ int main()

const size_t len = 256;
char buf[len];
buf[0] = '\0';
char* p = fgets(buf, len, out);
cout << "STDOUT: " << buf;
print_result(is, p!=NULL);

buf[0] = '\0';
p = fgets(buf, len, err);
cout << "STDERR: " << buf;
print_result(is, p!=NULL);
Expand All @@ -730,17 +732,94 @@ int main()
#if 0
size_t len = 256;
char buf[len];
buf[0] = '\0';
char* p = fgets(buf, len, out);
cout << "STDOUT: " << buf;
print_result(ps, p!=NULL);

buf[0] = '\0';
p = fgets(buf, len, err);
cout << "STDERR: " << buf;
print_result(ps, p!=NULL);
#endif
}
#endif

clog << "# Testing file descriptor access\n";

{
opstream os("tr '[:lower:]' '[:upper:]' | sed 's/^/STDIN: /'");
int in, out, err;
size_t res = os.fds(in, out, err);
print_result(os, res & pstreambuf::pstdin);
print_result(os, in!=-1);
const char *msg = "flax\n";
ssize_t i = write(in, msg, strlen(msg));
print_result(os, i==static_cast<ssize_t>(strlen(msg)));
}

{
std::string cmd = "ls /etc/hosts /no/such/file";
ipstream is(cmd, pstreambuf::pstdout|pstreambuf::pstderr);
int in, out, err;
size_t res = is.fds(in, out, err);
print_result(is, res & pstreambuf::pstdout);
print_result(is, res & pstreambuf::pstderr);
print_result(is, out!=-1);
print_result(is, err!=-1);

const size_t len = 256;
char buf[len];
ssize_t i = read(out, buf, len);
ssize_t count = 0;
if (i > 0) {
count = i;
}
cout << "STDOUT: " << std::string(buf, count);
print_result(is, i>=0);

i = read(err, buf, len);
count = 0;
if ( i > 0) {
count = i;
}
cout << "STDERR: " << std::string(buf, count);
print_result(is, i>=0);
}

{
std::string cmd = "grep 127 -- - /etc/hosts /no/such/file";
pstream ps(cmd, all3streams);
int in, out, err;
size_t res = ps.fds(in, out, err);
print_result(ps, res & pstreambuf::pstdin);
print_result(ps, res & pstreambuf::pstdout);
print_result(ps, res & pstreambuf::pstderr);
print_result(ps, in!=-1);
print_result(ps, out!=-1);
print_result(ps, err!=-1);

// ps << "12345\n1112777\n0000" << EOF;
#if 0
const size_t len = 256;
char buf[len];
ssize_t i = read(out, buf, len);
ssize_t count = 0;
if (i > 0) {
count = i;
}
cout << "STDOUT: " << std::string(buf, count);
print_result(is, i>=0);

i = read(err, buf, len);
count = 0;
if ( i > 0) {
count = i;
}
cout << "STDERR: " << std::string(buf, count);
print_result(is, i>=0);
#endif
}

clog << "# Testing resources freed correctly\n";

Expand Down