I'm new to programming, and I'm trying to write a c++ program for Linux which would create a child process, and this child process would execute an external program. The output of this program should be redirected to the main program and saved into a string variable, preserving all the spaces and new lines. I don't know how many lines/characters will the output contain.
This is the basic idea:
#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
int pipeDescriptors[2];
pipe(pipeDescriptors);
pid_t pid = fork();
if (pid == -1)
{
std::cerr << __LINE__ << ": fork() failed!\n" <<
std::strerror(errno) << '\n';
return 1;
}
else if (!pid)
{
// Child process
close(pipeDescriptors[0]); // Not gonna read from here
if (dup2(pipeDescriptors[1], STDOUT_FILENO) == -1) // Redirect output to the pipe
{
std::cerr << __LINE__ << ": dup2() failed!\n" <<
std::strerror(errno) << '\n';
return 1;
}
close(pipeDescriptors[1]); // Not needed anymore
execlp("someExternalProgram", "someExternalProgram", NULL);
}
else
{
// Parent process
close(pipeDescriptors[1]); // Not gonna write here
pid_t stdIn = dup(STDIN_FILENO); // Save the standard input for further usage
if (dup2(pipeDescriptors[0], STDIN_FILENO) == -1) // Redirect input to the pipe
{
std::cerr << __LINE__ << ": dup2() failed!\n" <<
std::strerror(errno) << '\n';
return 1;
}
close(pipeDescriptors[0]); // Not needed anymore
int childExitCode;
wait(&childExitCode);
if (childExitCode == 0)
{
std::string childOutput;
char c;
while (std::cin.read(&c, sizeof(c)))
{
childOutput += c;
}
// Do something with childOutput...
}
if (dup2(stdIn, STDIN_FILENO) == -1) // Restore the standard input
{
std::cerr << __LINE__ << ": dup2() failed!\n" <<
std::strerror(errno) << '\n';
return 1;
}
// Some further code goes here...
}
return 0;
}
The problem with the above code is that when std::cin.get()
function reads the last byte in the input stream, it doesn't actually "know" that this byte is the last one and tries to read further, which leads to set failbit
and eofbit
for std::cin
so I cannot read from the standard input later anymore. std::cin.clear()
resets those flags, but stdin
still remains unusable.
If I could get the precise size in bytes of the stdin
content without going beyond the last character in the stream, I would be able to use std::cin.read()
for reading this exact amount of bytes into a string variable. But I guess there is no way to do that.
So how can I solve this problem? Should I use an intermediate file for writing the output of the child process into it and reading it later from the parent process?