2

Bi-directional popen() functionality was added in FreeBSD 2.2.6 and is available in MacOS. I have a C program that writes a stream of newline-separated strings, and I'd like for it to pipe this to a Perl tool I wrote called cols that reads such a stream from STDIN, buffers it, and then writes it to STDOUT in a multicolumn, vertically-sorted format.

In the C program, I use:

FILE *cols_pipe = popen("cols", "r+"); to open the pipe and start cols;

fprintf( cols_pipe, "%s\n", word ); to send each newline-terminated word to cols; and

while ((getline(&line_buf, &line_buf_len, cols_pipe)) != -1) {
     printf("%s", line_buf);
}

to read back and print the reformatted lines from cols. When the program hung at getline() I realized it was because cols hadn't received EOF on STDIN, but closing cols_pipe (the only way I can think of to send EOF) would prevent me from reading back.

Obviously, cols can't begin to write its output until it's read all the input.

Any suggestions on how to achieve this? The C program is interactive so I don't want to simply invoke it from the command line with STDOUT piped to cols.

7
  • 1
    Sounds more like a buffering issue. Maybe you need a setvbuf() on cols_pipe to disable buffering or make it line-based or call fflush() after your fprintf() Commented Sep 4, 2022 at 17:36
  • 1
    You'll likely also want to disable buffering in perl for the reverse direction (see perldoc -v '$|') Commented Sep 4, 2022 at 17:40
  • @StéphaneChazelas I added those but it still hangs, presumably because Perl program is still waiting to read EOF.
    – Chap
    Commented Sep 4, 2022 at 17:54
  • 1
    If the perl program does @all_lines=<STDIN> and the print "something" then yes, it waits for EOF and you can't use popen(r+). If it does while(<STDIN>){print "something";} reading one line at a time, then you should be able to interact with it with your cols_pipe, but you'll likely still have a problem in the end if you need to signify EOF to cols and still read more output from it after that. You'd probably be better of using two pipes or a socketpair where you can shutdown directions independently. I've never used FreeBSD's popen(r+) or bidirectional pipes, they don't seem very useful Commented Sep 4, 2022 at 19:25
  • 1
    Also note that if cols starts outputting something before it has finished reading its input, you may end up in a deadlock situation if the data to be processed doesn't fit whole in the pipe buffer if at the other end you don't start reading cols output until you've finished send data to it. Commented Sep 4, 2022 at 19:31

1 Answer 1

1

Since the Perl program (as written) expects EOF on STDIN, and the only way to effect this is to close the input pipe, this won't work with popen(). Since you own the Perl code, however, you might consider adding a command option to defines a special token that indicates "end of input", much in the grand tradition of "heredocs", so that it can recognize the end of the input stream and begin to respond without the input pipe being closed.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .