启动后写入NSTasks标准输入

时间:2011-06-14 22:05:17

标签: objective-c redirect stdin nstask nsfilehandle

我目前正试图绕过NSTask,NSPipe,NSFileHandle业务。所以我想我写了一个小工具,它可以编译和运行C代码。我还希望能够将我的stdout和stdin重定向到文本视图。

这是我到目前为止所得到的。 我使用此帖子中的代码重定向我的stdio:What is the best way to redirect stdout to NSTextView in Cocoa?

NSPipe *inputPipe = [NSPipe pipe];
// redirect stdin to input pipe file handle
dup2([[inputPipe fileHandleForReading] fileDescriptor], STDIN_FILENO);
// curInputHandle is an instance variable of type NSFileHandle
curInputHandle = [inputPipe fileHandleForWriting];

NSPipe *outputPipe = [NSPipe pipe];
NSFileHandle *readHandle = [outputPipe fileHandleForReading];
[readHandle waitForDataInBackgroundAndNotify];
// redirect stdout to output pipe file handle
dup2([[outputPipe fileHandleForWriting] fileDescriptor], STDOUT_FILENO);

// Instead of writing to curInputHandle here I would like to do it later
// when my C program hits a scanf
[curInputHandle writeData:[@"123" dataUsingEncoding:NSUTF8StringEncoding]];

NSTask *runTask = [[[NSTask alloc] init] autorelease];
[runTask setLaunchPath:target]; // target was declared earlier
[runTask setArguments:[NSArray array]];
[runTask launch];

NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(stdoutDataAvailable:) name:NSFileHandleReadCompletionNotification object:readHandle];

这里是stdoutDataAvailable方法

- (void)stdoutDataAvailable:(NSNotification *)notification
{
    NSFileHandle *handle = (NSFileHandle *)[notification object];
    NSString *str = [[NSString alloc] initWithData:[handle availableData] encoding:NSUTF8StringEncoding];
    [handle waitForDataInBackgroundAndNotify];
    // consoleView is an NSTextView
    [self.consoleView setString:[[self.consoleView string] stringByAppendingFormat:@"Output:\n%@", str]];
}

本程序运作正常。它正在运行C程序将stdout打印到我的文本视图并从我的inputPipe读取“123”。如上面的评论所示,我想在任务需要时提供输入。

现在有两个问题。

  1. 有人试图从我的inputPipe读取数据时,有没有办法收到通知?
  2. 如果1的答案为否,我可以尝试不同的方法吗?也许使用NSTask以外的类?
  3. 非常感谢任何帮助,示例代码,指向其他资源的链接!

1 个答案:

答案 0 :(得分:2)

我不确定你是否能在NSPipe上发现“拉”。我确实有一种模糊的感觉,即使用select()轮询写入可用性或使用kqueueNSFileHandle的基础文件描述符上查找I / O可用性事件可能会起作用,但是我不太熟悉以这种方式使用这些设施。

您是否必须支持任意C程序,或者它是一个特殊的守护程序还是您开发的东西?

如果这是您自己的程序,您可以在outputPipe上查看反馈请求,或者只是在您发现要发送的内容时将输入信息发送到inputPipe,然后让C程序在准备就绪时会消耗它;如果它是其他人的代码,您可以使用链接时方法(因为它是您正在编译的代码)来挂钩scanf和朋友,就像附录A-4 中描述的那样的:

http://www.cs.umd.edu/Library/TRs/CS-TR-4585/CS-TR-4585.pdf

它的要点是使用您的自定义I / O函数创建.dylib(可能会向您的应用发送一些信号,表明它们需要输入),将其链接到构建的程序中,设置环境变量(DYLD_BIND_AT_LAUNCH=YES)用于已启动的任务,然后运行它。一旦你有了这些钩子,你可以提供你想要的主机程序的任何便利。