2

I'm launching some interactive process inside my OS X app I want to be able to read and write from pipes.

For example: Launching the process will wait for user to type command. When user is finished (aka pressed enter), process will return something and then again wait for user.

For now, I'm using NSPipe class for communication, but the problem is when method writeData: is called, I have to call closeFile in order to get notification NSFileHandleDataAvailableNotification.

Complete code (with changed folder paths) is this

dispatch_queue_t taskQueue =
   dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
  dispatch_async(taskQueue, ^{

    task = [[NSTask alloc] init];
    [task setStandardOutput: [NSPipe pipe]];
    [task setStandardInput: [NSPipe pipe]];
    [task setStandardError: [task standardOutput]];
    [task setLaunchPath: @"/Users/..."];
    [task setArguments:@[@"--interaction"]];

    [[[task standardOutput] fileHandleForReading] waitForDataInBackgroundAndNotify];

    [[NSNotificationCenter defaultCenter]
        addObserverForName:NSFileHandleDataAvailableNotification
                    object:[[task standardOutput] fileHandleForReading]
                     queue:nil
                usingBlock:^(NSNotification *notification){
        NSData *output = [[[task standardOutput] fileHandleForReading] availableData];
        NSString *outStr = [[NSString alloc] initWithData:output encoding:NSUTF8StringEncoding];
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"avaliable data: %@", outStr);
            NSString * message = @"IOTCM \"/Users/.../Demo.agda\" None Indirect ( Cmd_show_version )";
            [[[task standardInput] fileHandleForWriting] 
                   writeData:[message dataUsingEncoding:NSUTF8StringEncoding]];
        });
        [[[task standardOutput] fileHandleForReading] waitForDataInBackgroundAndNotify];
    }];

    [task launch];
    [task waitUntilExit];
});

Note that I get first notification (process is responding), but no notification comes after writeData: gets called.

How to achieve communication, that:

  1. gets launched (and stays launched through app lifecycle)

  2. writing and reading is supported

NSGod
  • 22,699
  • 3
  • 58
  • 66
markich
  • 356
  • 4
  • 10
  • 1
    Don't you need a newline at the end of the command? – Droppy May 23 '15 at 19:18
  • Maybe? Will try and accept if this does the trick. And I will buy you a beer, if this works :) thanks! – markich May 23 '15 at 19:20
  • If you live in Germany then I will bite your hand off for the beer ;-) – Droppy May 23 '15 at 19:21
  • Unfortunately no, but I will come to Oktoberfest and buy you a "kriegel" of beer! That works!!! :)))) Gosh, why isn't this in the documentation? Or is this a "general knowledge"? I'm new to pipes all all this IPC voodoo stuff... Anyway, Danke shon! – markich May 24 '15 at 10:09
  • Maybe you can write complete answer, so I can accept it? Maybe there is someone who is also smashing head against keyboard this moment because of this :D – markich May 24 '15 at 10:10
  • OK will do. I am actually English and just speak German beer, not the language :D – Droppy May 24 '15 at 13:24

1 Answers1

1

You need to append a newline to any commands you send to the pipe, in the same way you would interactively. Newlines flush stream buffers and are, in general, the "go" part of the command.

I cannot find any reference to re-enforce this answer, however.

Droppy
  • 9,691
  • 1
  • 20
  • 27