Re: NSTask, NSPipe's and interactive UNIX command
Re: NSTask, NSPipe's and interactive UNIX command
- Subject: Re: NSTask, NSPipe's and interactive UNIX command
- From: Chris Kane <email@hidden>
- Date: Wed, 2 Jan 2002 14:07:17 -0800
On Wednesday, January 2, 2002, at 06:40 AM, Nicola Vitacolonna wrote:
I have a problem with a wrapper I wrote for an interactive UNIX command.
[...]
So far, so good. Some information about what "command" does may be
useful too: "command" prints some text on screen (using a sequence of
printf()) and then waits for a character to be pressed (by calling
getchar()) before printing some other output. Something like that:
for (i=0;i<100; i++)
printf("aaaaaaaaaaaaaaaaaaaaaaaaa");
getchar();
printf("zzzzzzzzzzzzzzzzzzzzzzzzz");
The problem is that notifications of available data on the output pipe
are fired only *after* "command" has exited! That is, the behaviour of
this code is as follows: "command" is run but no output is shown;
however, if the user presses a key, this is correctly sent to the input
pipe, so "command" (which was hanging on getchar()) goes on, writes
some other text and exits. At this point only notifications of available
data are sent, so the program displays all the output of "command",
before and after getchar()! I do not understand why. Can someone give me
some hint? Am I doing something wrong? If this is a bug, does a
workaround exist?
The problem is likely that the stdio library inside is buffering
output. The output will only appear in the read pipe when the
command-line program flushes it, either because it writes a "\n" via the
stdio library, or fflush()s, or the buffer gets full, or exits (which
causes the stdio library to automatically flush any output still
buffered), or possibly some other conditions. If those printf strings
were "\n"-terminated, then you MIGHT the output quicker. That's because
there are three output buffering styles -- unbuffered, line-buffered (\n
causes a flush), and block buffered (when the output buffer gets full,
it's auto-flushed).
Buffering of stdout is line-buffered by default if the output file
descriptor is a tty (or pty); otherwise, block buffered. stderr is by
default unbuffered. The setvbuf() function is used to change the
buffering mode. These are all standard BSD UNIX (and maybe general
UNIX) things I've described here.
NSTask does not do any setting up of ttys/ptys for you. It wouldn't
help in this case anyway since the printfs aren't printing out \n.
Now, the problem is that the setvbuf() needs to be executed inside the
command-line program. Unless (1) you have the source to the
command-line program and can modify it and use that modified program, or
(2) the command-line program has a feature that allows you to tell it to
not buffer its output [ie, call setvbuf() itself], there's no way to
change this, that I know of. The parent simply cannot affect the
subprocess in this way, either to force flushing at certain points or
change the stdio buffering behavior, unless the command-line utility has
those features built into it (which would be rare).
Chris Kane
Cocoa Frameworks, Apple