5

我目前正试图围绕 NSTask、NSPipe、NSFileHandle 业务的漏洞。所以我想我写一个小工具,可以编译和运行C代码。我还希望能够将我的标准输出和标准输入重定向到文本视图。

这是我到目前为止得到的。我使用这篇文章中的代码来重定向我的 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];

这里是 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]];
}

该程序运行良好。它正在运行将标准输出打印到我的文本视图并从我的 inputPipe 读取“123”的 C 程序。就像我在上面的评论中指出的那样,我想在需要时在任务运行时提供输入。

所以现在有两个问题。

  1. 有没有办法在有人尝试从我的 inputPipe 读取数据时立即收到通知?
  2. 如果 1 的答案是否定的,我可以尝试其他方法吗?也许使用 NSTask 以外的类?

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

4

1 回答 1

2

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

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

如果它是您自己的程序,您可以观察对 的反馈请求outputPipe,或者在inputPipe您发现要发送的内容时将输入发送到 ,并在准备好时让 C 程序使用它;如果它是其他人的代码,您可以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为启动的任务设置环境变量 (),以及运行。一旦你有了这些钩子,你就可以为你的主机程序提供任何你想要的便利。

于 2011-06-27T19:31:24.777 回答