In a X function, I am using pipes, to buffer(couple of printfs
, which are printed in Y function called inside from X function) the stdout
stream if one Fd and then after buffer is complete,close one pipe and other Fd and then use printf
on it.
I want to be completely sure that buffer is empty, when next time this X function is called again to do the task.
I tried couple of things which I found online:
fflush
ioctl
, _flushlbf
: looks like they aren't supported by gcc. Does g++ support it?
fseek(stdin,EOF,SEEK_END);
fpurge(ofp);
I call X()
function, couple of times. The present code, I have written, works fine if next set of output is greater than previous set.
If next set of output is less the present set of output. Then next set have some extra garbage values, which gives me an indication , that buffer may have not flushed completely.
Because of certain reason, I have written entire code in C but using g++ compiler.
My code as follows:
void X(int pairs,char* expOut)
{
char buf[256];
int fds[2];
char output[300];
char input[50];
/* opening pipes */
pipe(fds);
/* saving the the given stdout stream */
int bak = dup(STDOUT_FILENO);
/* associating Fds[1] pipe with stdout */
int res=dup2(fds[1],STDOUT_FILENO);
/* associating Fds[0] pipe with stdin */
dup2(fds[0],STDIN_FILENO);
assert(res!=-1);
/* Call To function Y: function combParenthesis is a recursive function,
which prints out some strings couple of time */
combParenthesis(pairs) ;
fflush(stdout);
/* closing stdout FD stream */
close(fds[1]);
fflush(stdout);
/* restoring the old stdout stream */
dup2(bak, 1);
close(bak);
/* opening, stdin stream for reading */
FILE *ofp = fdopen(fds[0], "r");
char strs[30][30];
for (int i=0;i<30;i++) {
memset(strs[i], 0, 30);
}
int i=0;
if (ofp)
{
int sz;
if((pairs*2)+1 <= 1)
{
sz=5;
}
else
{sz = (pairs*2)+1 ;}
/* read the stream line by line */
while (fgets(buf,sz ,ofp)) {
printf("\n next string %s", buf);
i++;
}
if (ferror(ofp)) {
printf("something went wrong in the input to printf");
}
}
/* different ways to flush it out */
char c;
while( (c = fgetc( ofp )) != EOF && c != '\n' );
fseek(stdin,EOF,SEEK_END);
fpurge(ofp);
fclose(ofp);
fflush(stdin);
// _flushlbf();
/* close the fd associated with stdin */
close(fds[0]);
}
EDIT: a precision at the end on fflush
positioning.
I managed to run your code simply using a combParenthesis
of my own (first pass : medium strings, second : larger strings, third smaller). I never found garbage in output ... as soon as I have replaced your printf("\n next string %s", buf);
by an output on stderr
fprintf(stderr, "\n next string %s", buf);
I also got correct output by flushing stdout after stdin and ofp by a single fflush(stdout)
. IMHO the problem was :
- you close the pipe so stdout is no longer copied to ofp or stdin
- you write on stdout with
printf("\n next string %s", buf)
and stdout may be buffered
- you flush streams that are allready clean
- when you dup stdout on your next call, you may read what remained from last pass in stdout
Here are the main improvements that I found :
- if your read output of
combParenthesis
with a pipe duping stdout, never write to stdout in any over place (or be sure to flush it)
- you do an unnecessary
dup2(fds[0],STDIN_FILENO);
because you directly read on the other end of the pipe (which is better)
- you never verify that
sz = (pairs*2)+1
is smaller than sizeof(buf)
Edit : In fact, I have just realized that your code could work, even with intermixed printf
elsewhere in the application, provided you flush stdout before copying it to fds[1].
So here is a fixed version of your X()
function with clearly identified edits (but IMHO you should considered my other suggestions too) :
void X(int pairs,char* expOut)
{
char buf[256];
int fds[2];
char output[300];
char input[50];
/* BEGIN EDIT */
/* first flush stdout */
fflush(stdout);
/* END EDIT */
/* opening pipes */
pipe(fds);
/* saving the the given stdout stream */
int bak = dup(STDOUT_FILENO);
/* associating Fds[1] pipe with stdout */
int res=dup2(fds[1],STDOUT_FILENO);
/* associating Fds[0] pipe with stdin */
dup2(fds[0],STDIN_FILENO);
assert(res!=-1);
/* Call To function Y: function combParenthesis is a recursive function,
which prints out some strings couple of time */
combParenthesis(pairs) ;
/* closing stdout FD stream */
close(fds[1]);
fflush(stdout);
/* restoring the old stdout stream */
dup2(bak, 1);
close(bak);
/* opening, stdin stream for reading */
FILE *ofp = fdopen(fds[0], "r");
char strs[30][30];
for (int i=0;i<30;i++) {
memset(strs[i], 0, 30);
}
int i=0;
if (ofp)
{
int sz;
if((pairs*2)+1 <= 1)
{
sz=5;
}
else
{sz = (pairs*2)+1 ;}
/* read the stream line by line */
// EDIT : changed sz with sizeof(buf)-1 - cause: no correct pairs value
while (fgets(buf, sizeof(buf) - 1,ofp)) {
printf("\n next string %s", buf);
i++;
}
if (ferror(ofp)) {
printf("something went wrong in the input to printf");
}
}
/* different ways to flush it out */
/* BEGIN EDIT : ALL FLUSHING COMMENTED OUT
char c;
while( (c = fgetc( ofp )) != EOF && c != '\n' );
fseek(stdin,EOF,SEEK_END);
fpurge(ofp);
fclose(ofp);
fflush(stdin);
// _flushlbf();
END EDIT */
/* close the fd associated with stdin */
close(fds[0]);
}
I never got garbage in what is read and it works even with output redirected to a file, but for a reason I couldn't explain, the order of the messages is not what I would expect. Hope it's not a concern for you