1 /////////////////////////////////////////////////////////////////////////////
 
   2 // Name:        src/cocoa/utilsexec.mm
 
   3 // Purpose:     Execution-related utilities for wxCocoa
 
   8 // Copyright:   (c) Ryan Norton
 
   9 // Licence:     wxWindows licence
 
  10 // Notes:       This code may be useful on platforms other than Darwin.
 
  11 //              On Darwin we share the CoreFoundation code with wxMac.
 
  12 /////////////////////////////////////////////////////////////////////////////
 
  14 #include "wx/wxprec.h"
 
  17 #include "wx/unix/execute.h"
 
  24 #include "wx/process.h"
 
  25 #include "wx/stream.h"
 
  27 #include "wx/cocoa/string.h"
 
  29 #import <Foundation/Foundation.h>
 
  30 #import <AppKit/NSWorkspace.h>
 
  33 // RN:  This is a prelimenary implementation - simple
 
  34 // launching and process redirection works,
 
  35 // but with the piping tests in the exec sample
 
  36 // SIGPIPE is triggered...
 
  39 class wxPipeInputStream : public wxInputStream
 
  42     wxPipeInputStream(NSPipe* thePipe) : 
 
  44             m_theHandle([m_thePipe fileHandleForReading])
 
  54     virtual size_t OnSysRead(void *buffer, size_t size)
 
  56         NSData* theData = [m_theHandle readDataOfLength:size];
 
  57         memcpy(buffer, [theData bytes], [theData length]);
 
  58         return [theData length];
 
  63     NSFileHandle*       m_theHandle;
 
  66 class wxPipeOutputStream : public wxOutputStream
 
  69     wxPipeOutputStream(NSPipe* thePipe) : 
 
  71             m_theHandle([m_thePipe fileHandleForWriting])
 
  82     virtual size_t OnSysWrite(const void *buffer, size_t bufsize)
 
  84         NSData* theData = [NSData dataWithBytesNoCopy:(void*)buffer 
 
  86         [m_theHandle writeData:theData];
 
  91     NSFileHandle*       m_theHandle;
 
  94 @interface wxTaskHandler : NSObject
 
  99 -(id)init:(void*)handle processIdentifier:(long)pid;
 
 100 - (void)termHandler:(NSNotification *)aNotification;
 
 103 @implementation wxTaskHandler : NSObject
 
 105 -(id)init:(void*)handle processIdentifier:(long)pid 
 
 112     [[NSNotificationCenter defaultCenter] addObserver:self 
 
 113             selector:@selector(termHandler:) 
 
 114             name:NSTaskDidTerminateNotification 
 
 119 - (void)termHandler:(NSNotification *)aNotification 
 
 121     NSTask* theTask = [aNotification object];
 
 123     if ([theTask processIdentifier] == m_pid)
 
 125         ((wxProcess*)m_handle)->OnTerminate([theTask processIdentifier], 
 
 126                           [theTask terminationStatus]);
 
 134 long wxExecute(const wxString& command, 
 
 138     NSTask* theTask = [[NSTask alloc] init];
 
 140     if (handle && handle->IsRedirected())
 
 142         NSPipe* theStdinPipe = [[NSPipe alloc] init];
 
 143         NSPipe* theStderrPipe = [[NSPipe alloc] init];
 
 144         NSPipe* theStdoutPipe = [[NSPipe alloc] init];
 
 146         [theTask setStandardInput:theStdinPipe];
 
 147         [theTask setStandardError:theStderrPipe];
 
 148         [theTask setStandardOutput:theStdoutPipe];
 
 150         handle->SetPipeStreams(new wxPipeInputStream(theStdoutPipe),
 
 151                                new wxPipeOutputStream(theStdinPipe),
 
 152                                new wxPipeInputStream(theStderrPipe) );
 
 155     NSArray* theQuoteArguments = 
 
 156         [wxNSStringWithWxString(command) componentsSeparatedByString:@"\""];
 
 158     NSMutableArray* theSeparatedArguments = 
 
 159         [NSMutableArray arrayWithCapacity:10];
 
 161     for (unsigned i = 0; i < [theQuoteArguments count]; ++i)
 
 163         [theSeparatedArguments addObjectsFromArray:
 
 164             [[theQuoteArguments objectAtIndex:i] componentsSeparatedByString:@" "]
 
 167         if(++i < [theQuoteArguments count])
 
 168             [theSeparatedArguments addObject:[theQuoteArguments objectAtIndex:i]];
 
 171     [theTask setLaunchPath:[theSeparatedArguments objectAtIndex:0]];
 
 172     [theTask setArguments:theSeparatedArguments];
 
 175     if(sync & wxEXEC_ASYNC)
 
 177         [[wxTaskHandler alloc]init:handle 
 
 178                               processIdentifier:[theTask processIdentifier]];
 
 184         [theTask waitUntilExit];
 
 186         return [theTask terminationStatus];