Re: stdout redirect in xcode and not
Re: stdout redirect in xcode and not
- Subject: Re: stdout redirect in xcode and not
- From: Aaron Burghardt <email@hidden>
- Date: Fri, 02 Jan 2009 08:43:34 -0500
Hi Wesley,
If you disable caching on stdout/stderr, you shouldn't need to
fflush() and poll. I am thinking of using this technique, too, so
thanks for the idea. I created a test app to try it it, which is
listed below. This example demonstrates a Cocoa implementation, but
that isn't a requirement, though it does make it easy to deal with
waiting for data. This sample also requires a NIB with an instance of
AppController, an NSTextView and a NSButton. When the button is
clicked, the stderr message is immediately added to the log text
view. One nuisance with this sample is that NSLog() messages result
in two instances of the message in the system log.
Aaron
AppController.h:
@interface AppController : NSObject
{
IBOutlet NSTextView *logTextView;
NSPipe *pipe;
}
- (IBAction)performTest:(id)sender;
@end
AppController.m:
#import "AppController.h"
#include <unistd.h>
#include <fcntl.h>
@implementation AppController
- (void)awakeFromNib
{
pipe = [[NSPipe pipe] retain];
NSFileHandle *readHandle = [pipe fileHandleForReading];
NSFileHandle *writeHandle = [pipe fileHandleForWriting];
fcntl([readHandle fileDescriptor], F_NOCACHE);
fcntl([writeHandle fileDescriptor], F_NOCACHE);
if (dup2([writeHandle fileDescriptor], STDERR_FILENO) == -1) {
printf("failed to dup to stderr: (%i) %s\n", errno, strerror(errno));
return;
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleStandardErrorNotification:)
name:NSFileHandleDataAvailableNotification
object:readHandle];
[readHandle waitForDataInBackgroundAndNotify];
}
- (void)handleStandardErrorNotification:(NSNotification *)notif
{
NSData *data = [[notif object] availableData];
NSString *string = [[NSString alloc] initWithBytesNoCopy:(char *)
[data bytes]
length:[data length]
encoding:NSUTF8StringEncoding
freeWhenDone:NO];
NSAttributedString *message = [[NSAttributedString alloc]
initWithString:string];
[[logTextView textStorage] appendAttributedString:message];
[string release];
[message release];
[[notif object] waitForDataInBackgroundAndNotify];
}
- (IBAction)performTest:(id)sender
{
fprintf(stderr, "Current time: %s\n", [[[NSDate date] description]
UTF8String]);
}
On Dec 24, 2008, at 1:42 AM, Wesley Smith wrote:
Just to follow up, especially since it's hard to find precise info on
this subject on the interwebs. The problem I was trying to solve was
how to direct stdout and stderr to an arbitrary memory buffer inside
an application. In my case, I'm directing to to a console window and
a log file.
In the end, I had to use a polling method as I couldn't find any way
to get callbacks when a pipe has data to read off the read endpoint.
The setup looks like this:
FILE *readStream;
int spipe[2];
if(pipe(spipe) != 0) {
// error
}
for(int n=0; n < 2; n++) {
int f = fcntl(spipe[n], F_GETFL, 0);
f |= O_NONBLOCK;
fcntl(spipe[n], F_SETFL, f);
}
readStream = fdopen(spipe[0], "r");
dup2(spipe[1], fileno(stdout));
Then, you have to poll the readStrem FILE structure as follows:
std::string str;
int res = 0;
fflush(stdout);
do {
char buffer[128];
res = fread(buffer, 1, 127, readStream);
buffer[res] = '\0';
str.append(buffer);
} while(res > 0);
Obviously, the method of collecting chunks of data from the FILE can
differ, but it is essential yo call fflush on stdout (or stderr as the
case may be). I've found that not calling fflush results in nothing
being read by fread.
wes
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Xcode-users mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Xcode-users mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden