启动后写入NSTasks标准输入

Jan*_*nek 5 redirect stdin objective-c nstask nsfilehandle

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

这是我到目前为止所得到的.我使用这篇文章中的代码来重定向我的stdio:在Cocoa中将stdout重定向到NSTextView的最佳方法是什么?

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];
Run Code Online (Sandbox Code Playgroud)

这里是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]];
}
Run Code Online (Sandbox Code Playgroud)

这个程序工作得很好.它正在运行C程序将stdout打印到我的文本视图并从我的inputPipe读取"123".如上面的评论所示,我想在任务需要时提供输入.

所以现在有两个问题.

  1. 有人试图从我的inputPipe读取数据时有没有办法收到通知?
  2. 如果1的答案是否定的,我可以尝试不同的方法吗?也许使用NSTask以外的课程?

任何帮助,示例代码,其他资源的链接都非常感谢!

Joe*_*orn 2

我不确定您是否可以检测到NSPipe. 我确实有一种模糊的感觉,轮询写入可用性select()或使用kqueue在底层文件描述符上查找 I/O 可用性事件NSFileHandle可能会成功,但我不太熟悉以这种方式使用这些设施。

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

如果是您自己的程序,您可以监视 上的反馈请求,或者当您发现要发送的内容时将其outputPipe输入到 上,并在准备好时让 C 程序使用它;inputPipe如果它是其他人的代码,您可以scanf使用链接时方法(因为它是您正在编译的代码)来挂钩和朋友,如附录 A-4中所述:

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

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

  • 我不完全确定在一般情况下,您是否可以知道程序是否需要输入。请记住,还有一些程序使用 select 或 kqueue 来监视输入管道的活动(再次问候!)。作为旁注,如果您愿意,您可以使用单个 NSTextView 进行输入和输出(请参阅 [PseudoTTY 项目](http://amath.colorado.edu/pub/mac/programs/),了解一些稍微旧但可能仍然有用的源代码)。FWIW,我相信即使是 `Terminal.app` 也会愉快地接受输入,而不关心正在运行的程序是否需要它,对吧? (2认同)