Question

I have a C function that prints to stdout using fprintf, and I'm attempting to display the contents of stdout in a UIAlertView. My code is as follows:

NSFileHandle *stdoutFileHandle = [NSFileHandle fileHandleWithStandardOutput];
NSData *stdoutData = [stdoutFileHandle availableData];
NSString *stdoutString = [[NSString alloc] initWithData:stdoutData encoding:NSASCIIStringEncoding];

UIAlertView *stdoutAlert = [[UIAlertView alloc] initWithTitle:@"STDOUT OUTPUT" message:stdoutString delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[stdoutAlert show];

I'm getting the following error when I run my code.

Terminating app due to uncaught exception 'NSFileHandleOperationException', reason: '[NSConcreteFileHandle availableData]: Bad file descriptor'

I get an equivalent error when I replace [stdoutFileHandle availableData] with [stdoutFileHandle readDataToEndOfFile].

Was it helpful?

Solution

The problem is you are reading from a output stream. To make this work you need to trick stdout to write it's contents to an input stream instead of to the console.

I know the old C way to do this, but you're not gonna like it. This uses pipe() and dup2().

int pipefd[2];

pipe(pipefd);
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[1]);

At this point anything written to stdout can be read by pipefd[0]. At that point you can use -initWithFileDescriptor: to read from pipefd[0].

NSFileHandle *stdoutReader = [[NSFileHandle alloc] initWithFileDescriptor:pipefd[0]];

Note, you will want to do lots of error checking. Hope that helps.

OTHER TIPS

I followed the selected answer post in this question: What is the best way to redirect stdout to NSTextView in Cocoa?

It felt a bit more familiar to follow for me. I created an NSPipe, and NSFileHandler object for the pipe and read handler and I used notifications. I put the open method below in the viewDidAppear and viewDidDisappear method because of my needs but you can put it wherever it's appropriate

// Piping stdout info from here WILL NOT PIPE NSLOG:
// https://stackoverflow.com/questions/2406204/what-is-the-best-way-to-redirect-stdout-to-nstextview-in-cocoa
- (void) openConsolePipe {
    _pipe = [NSPipe pipe];
    _pipeReadHandle = [_pipe fileHandleForReading] ;
    dup2([[_pipe fileHandleForWriting] fileDescriptor], fileno(stdout)) ;

    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleNotification:) name: NSFileHandleReadCompletionNotification object: _pipeReadHandle] ;
    [_pipeReadHandle readInBackgroundAndNotify] ;
}

- (void) closeConsolePipe {
    if (_pipe != nil) {
        [[_pipe fileHandleForWriting] closeFile];

        // documentation suggests don't need to close reading file handle b/c auto but this suggests otherwise:
        // https://stackoverflow.com/questions/13747232/using-nstask-and-nspipe-causes-100-cpu-usage
//        [[_pipe fileHandleForReading] closeFile];
    }
}

- (void) handleNotification:(NSNotification *)notification {
    [_pipeReadHandle readInBackgroundAndNotify] ;
    NSString *str = [[NSString alloc] initWithData: [[notification userInfo] objectForKey: NSFileHandleNotificationDataItem] encoding: NSUTF8StringEncoding];

    // do what you want with the str here.
    [_consoleView setText:[_consoleView.text stringByAppendingString:str]];
    [_consoleView scrollRangeToVisible:NSMakeRange([_consoleView.text length], 0)];
}

I hope this ends up helping someone else googling this...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top