Записать в стандартный ввод NSTasks после запуска
В настоящее время я пытаюсь обернуть голову вокруг дырки NSTask, NSPipe, NSFileHandle business. Поэтому я подумал написать небольшой инструмент, который может компилировать и запускать код на Си. Я также хотел иметь возможность перенаправить мой стандартный вывод и стандартный ввод в текстовое представление.
Вот что я получил до сих пор. Я использовал код из этого поста для перенаправления моего stdio: Каков наилучший способ перенаправить стандартный вывод в 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]];
}
Эта программа работает просто отлично. Он запускает программу C, которая выводит стандартный вывод в мое текстовое представление и читает "123" из моего inputPipe. Как указано в моем комментарии выше, я хотел бы предоставить входные данные, когда задача выполняется, когда это необходимо.
Итак, сейчас есть два вопроса.
- Есть ли способ получить уведомление, как только кто-то попытается прочитать данные из моего inputPipe?
- Если ответ на 1 - нет, могу ли я попробовать другой подход? Может быть, используя класс, отличный от NSTask?
Любая помощь, пример кода, ссылки на другие ресурсы высоко ценятся!
1 ответ
Я не уверен, что вы можете обнаружить "тянуть" на NSPipe
, У меня есть смутное ощущение, что опрос для доступности записи с select()
или используя kqueue
искать события доступности ввода / вывода в базовом файловом дескрипторе вашего NSFileHandle
может сделать свое дело, но я не очень знаком с использованием этих средств таким образом.
Вы должны поддерживать произвольные программы на C, или это специальный демон или что-то, что вы разработали?
Если это ваша собственная программа, вы можете отслеживать запросы на обратную связь outputPipe
или просто взорвать ввод на inputPipe
когда вы узнаете, что именно вы хотите отправить, и дайте программе на C потреблять ее, когда она будет готова; если это чужой код, вы можете подключить scanf
и друзья, использующие метод времени компоновки (так как это код, который вы компилируете), как описано в Приложении A-4:
http://www.cs.umd.edu/Library/TRs/CS-TR-4585/CS-TR-4585.pdf
Суть в том, чтобы сделать .dylib
с вашими пользовательскими функциями ввода / вывода (которые могут отправлять некоторые символы в ваше приложение, указывающие, что они нуждаются в вводе), связать это со встроенной программой, установить переменную среды (DYLD_BIND_AT_LAUNCH=YES
) для запущенного задания и запустите его. Получив эти хуки, вы можете предоставить любые удобства, которые вы хотите для своей хост-программы.