1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Execution-related utilities for wxCocoa
4 // Author: Ryan Norton (carbon darwin version based off of Stefan's code)
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 //#pragma implementation
19 #include "wx/unix/execute.h"
23 #include <mach/mach.h>
25 #include <CoreFoundation/CFMachPort.h>
34 long wxExecute(const wxString& command, int flags, wxProcess *WXUNUSED(handler))
36 wxFAIL_MSG( _T("wxExecute() not yet implemented") );
43 void wxMAC_MachPortEndProcessDetect(CFMachPortRef port, void *data)
45 wxEndProcessData *proc_data = (wxEndProcessData*)data;
46 wxLogDebug(wxT("Wow.. this actually worked!"));
48 int rc = waitpid(abs(proc_data->pid), &status, WNOHANG);
51 wxLogDebug(wxT("Mach port was invalidated, but process hasn't terminated!"));
54 if((rc != -1) && WIFEXITED(status))
55 proc_data->exitcode = WEXITSTATUS(status);
57 proc_data->exitcode = -1;
58 wxHandleProcessTermination(proc_data);
61 int wxAddProcessCallbackForPid(wxEndProcessData *proc_data, int pid)
65 kern_return_t kernResult;
66 mach_port_t taskOfOurProcess;
67 mach_port_t machPortForProcess;
68 taskOfOurProcess = mach_task_self();
69 if(taskOfOurProcess == MACH_PORT_NULL)
71 wxLogDebug(wxT("No mach_task_self()"));
74 wxLogDebug(wxT("pid=%d"),pid);
75 kernResult = task_for_pid(taskOfOurProcess,pid, &machPortForProcess);
76 if(kernResult != KERN_SUCCESS)
78 wxLogDebug(wxT("no task_for_pid()"));
79 // try seeing if it is already dead or something
80 // FIXME: a better method would be to call the callback function
81 // from idle time until the process terminates. Of course, how
82 // likely is it that it will take more than 0.1 seconds for the
83 // mach terminate event to make its way to the BSD subsystem?
84 usleep(100); // sleep for 0.1 seconds
85 wxMAC_MachPortEndProcessDetect(NULL, (void*)proc_data);
88 CFMachPortContext termcb_contextinfo;
89 termcb_contextinfo.version = NULL;
90 termcb_contextinfo.info = (void*)proc_data;
91 termcb_contextinfo.retain = NULL;
92 termcb_contextinfo.release = NULL;
93 termcb_contextinfo.copyDescription = NULL;
94 CFMachPortRef CFMachPortForProcess;
95 Boolean ShouldFreePort;
96 CFMachPortForProcess = CFMachPortCreateWithPort(NULL, machPortForProcess, NULL, &termcb_contextinfo, &ShouldFreePort);
97 if(!CFMachPortForProcess)
99 wxLogDebug(wxT("No CFMachPortForProcess"));
100 mach_port_deallocate(taskOfOurProcess, machPortForProcess);
105 kernResult = mach_port_deallocate(taskOfOurProcess, machPortForProcess);
106 if(kernResult!=KERN_SUCCESS)
108 wxLogDebug(wxT("Couldn't deallocate mach port"));
112 CFMachPortSetInvalidationCallBack(CFMachPortForProcess, &wxMAC_MachPortEndProcessDetect);
113 CFRunLoopSourceRef runloopsource;
114 runloopsource = CFMachPortCreateRunLoopSource(NULL,CFMachPortForProcess, (CFIndex)0);
117 wxLogDebug(wxT("Couldn't create runloopsource"));
121 CFRelease(CFMachPortForProcess);
123 CFRunLoopAddSource(CFRunLoopGetCurrent(),runloopsource,kCFRunLoopDefaultMode);
124 CFRelease(runloopsource);
125 wxLogDebug(wxT("Successfully added notification to the runloop"));
132 #pragma implementation
135 #include "wx/utils.h"
137 #include "wx/process.h"
138 #include "wx/stream.h"
140 #include "wx/cocoa/string.h"
142 #import <Foundation/Foundation.h>
143 #import <AppKit/NSWorkspace.h>
146 // RN: This is a prelimenary implementation - simple
147 // launching and process redirection works,
148 // but with the piping tests in the exec sample
149 // SIGPIPE is triggered...
152 class wxPipeInputStream : public wxInputStream
155 wxPipeInputStream(NSPipe* thePipe) :
157 m_theHandle([m_thePipe fileHandleForReading])
167 virtual size_t OnSysRead(void *buffer, size_t size)
169 NSData* theData = [m_theHandle readDataOfLength:size];
170 memcpy(buffer, [theData bytes], [theData length]);
171 return [theData length];
176 NSFileHandle* m_theHandle;
179 class wxPipeOutputStream : public wxOutputStream
182 wxPipeOutputStream(NSPipe* thePipe) :
184 m_theHandle([m_thePipe fileHandleForWriting])
188 ~wxPipeOutputStream()
195 virtual size_t OnSysWrite(const void *buffer, size_t bufsize)
197 NSData* theData = [NSData dataWithBytesNoCopy:(void*)buffer
199 [m_theHandle writeData:theData];
204 NSFileHandle* m_theHandle;
207 @interface wxTaskHandler : NSObject
212 -(id)init:(void*)handle processIdentifier:(long)pid;
213 - (void)termHandler:(NSNotification *)aNotification;
216 @implementation wxTaskHandler : NSObject
218 -(id)init:(void*)handle processIdentifier:(long)pid
225 [[NSNotificationCenter defaultCenter] addObserver:self
226 selector:@selector(termHandler:)
227 name:NSTaskDidTerminateNotification
232 - (void)termHandler:(NSNotification *)aNotification
234 NSTask* theTask = [aNotification object];
236 if ([theTask processIdentifier] == m_pid)
238 ((wxProcess*)m_handle)->OnTerminate([theTask processIdentifier],
239 [theTask terminationStatus]);
247 long wxExecute(const wxString& command,
251 NSTask* theTask = [[NSTask alloc] init];
253 if (handle && handle->IsRedirected())
255 NSPipe* theStdinPipe = [[NSPipe alloc] init];
256 NSPipe* theStderrPipe = [[NSPipe alloc] init];
257 NSPipe* theStdoutPipe = [[NSPipe alloc] init];
259 [theTask setStandardInput:theStdinPipe];
260 [theTask setStandardError:theStderrPipe];
261 [theTask setStandardOutput:theStdoutPipe];
263 handle->SetPipeStreams(new wxPipeInputStream(theStdoutPipe),
264 new wxPipeOutputStream(theStdinPipe),
265 new wxPipeInputStream(theStderrPipe) );
268 NSArray* theQuoteArguments =
269 [wxNSStringWithWxString(command) componentsSeparatedByString:@"\""];
271 NSMutableArray* theSeperatedArguments =
272 [NSMutableArray arrayWithCapacity:10];
274 for (unsigned i = 0; i < [theQuoteArguments count]; ++i)
276 [theSeperatedArguments addObjectsFromArray:
277 [[theQuoteArguments objectAtIndex:i] componentsSeparatedByString:@" "]
280 if(++i < [theQuoteArguments count])
281 [theSeperatedArguments addObject:[theQuoteArguments objectAtIndex:i]];
284 [theTask setLaunchPath:[theSeperatedArguments objectAtIndex:0]];
285 [theTask setArguments:theSeperatedArguments];
288 if(sync & wxEXEC_ASYNC)
290 [[wxTaskHandler alloc]init:handle
291 processIdentifier:[theTask processIdentifier]];
297 [theTask waitUntilExit];
299 return [theTask terminationStatus];