]> git.saurik.com Git - wxWidgets.git/blob - src/cocoa/utilsexc.mm
final sweep over docs - replace & with \&
[wxWidgets.git] / src / cocoa / utilsexc.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: utilsexec.mm
3 // Purpose: Execution-related utilities for wxCocoa
4 // Author: Ryan Norton (carbon darwin version based off of Stefan's code)
5 // Modified by:
6 // Created: 2004-10-05
7 // RCS-ID: $Id$
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 //#pragma implementation
14 #endif
15
16 #include "wx/log.h"
17 #include "wx/utils.h"
18 #ifdef __DARWIN__
19 #include "wx/unix/execute.h"
20 #include <unistd.h>
21 #include <sys/wait.h>
22 extern "C" {
23 #include <mach/mach.h>
24 }
25 #include <CoreFoundation/CFMachPort.h>
26 #endif
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #ifndef __DARWIN__
33
34 long wxExecute(const wxString& command, int flags, wxProcess *WXUNUSED(handler))
35 {
36 wxFAIL_MSG( _T("wxExecute() not yet implemented") );
37 return 0;
38 }
39
40 #endif
41
42 #ifdef __DARWIN__
43 void wxMAC_MachPortEndProcessDetect(CFMachPortRef port, void *data)
44 {
45 wxEndProcessData *proc_data = (wxEndProcessData*)data;
46 wxLogDebug(wxT("Wow.. this actually worked!"));
47 int status = 0;
48 int rc = waitpid(abs(proc_data->pid), &status, WNOHANG);
49 if(!rc)
50 {
51 wxLogDebug(wxT("Mach port was invalidated, but process hasn't terminated!"));
52 return;
53 }
54 if((rc != -1) && WIFEXITED(status))
55 proc_data->exitcode = WEXITSTATUS(status);
56 else
57 proc_data->exitcode = -1;
58 wxHandleProcessTermination(proc_data);
59 }
60
61 int wxAddProcessCallbackForPid(wxEndProcessData *proc_data, int pid)
62 {
63 if(pid < 1)
64 return -1;
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)
70 {
71 wxLogDebug(wxT("No mach_task_self()"));
72 return -1;
73 }
74 wxLogDebug(wxT("pid=%d"),pid);
75 kernResult = task_for_pid(taskOfOurProcess,pid, &machPortForProcess);
76 if(kernResult != KERN_SUCCESS)
77 {
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);
86 return -1;
87 }
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)
98 {
99 wxLogDebug(wxT("No CFMachPortForProcess"));
100 mach_port_deallocate(taskOfOurProcess, machPortForProcess);
101 return -1;
102 }
103 if(ShouldFreePort)
104 {
105 kernResult = mach_port_deallocate(taskOfOurProcess, machPortForProcess);
106 if(kernResult!=KERN_SUCCESS)
107 {
108 wxLogDebug(wxT("Couldn't deallocate mach port"));
109 return -1;
110 }
111 }
112 CFMachPortSetInvalidationCallBack(CFMachPortForProcess, &wxMAC_MachPortEndProcessDetect);
113 CFRunLoopSourceRef runloopsource;
114 runloopsource = CFMachPortCreateRunLoopSource(NULL,CFMachPortForProcess, (CFIndex)0);
115 if(!runloopsource)
116 {
117 wxLogDebug(wxT("Couldn't create runloopsource"));
118 return -1;
119 }
120
121 CFRelease(CFMachPortForProcess);
122
123 CFRunLoopAddSource(CFRunLoopGetCurrent(),runloopsource,kCFRunLoopDefaultMode);
124 CFRelease(runloopsource);
125 wxLogDebug(wxT("Successfully added notification to the runloop"));
126 return 0;
127 }
128 #endif
129
130 /*
131 #ifdef __GNUG__
132 #pragma implementation
133 #endif
134
135 #include "wx/utils.h"
136
137 #include "wx/process.h"
138 #include "wx/stream.h"
139
140 #include "wx/cocoa/string.h"
141
142 #import <Foundation/Foundation.h>
143 #import <AppKit/NSWorkspace.h>
144
145 //
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...
150 //
151
152 class wxPipeInputStream : public wxInputStream
153 {
154 public:
155 wxPipeInputStream(NSPipe* thePipe) :
156 m_thePipe(thePipe),
157 m_theHandle([m_thePipe fileHandleForReading])
158 {
159 }
160
161 ~wxPipeInputStream()
162 {
163 [m_thePipe release];
164 }
165
166 protected:
167 virtual size_t OnSysRead(void *buffer, size_t size)
168 {
169 NSData* theData = [m_theHandle readDataOfLength:size];
170 memcpy(buffer, [theData bytes], [theData length]);
171 return [theData length];
172 }
173
174
175 NSPipe* m_thePipe;
176 NSFileHandle* m_theHandle;
177 };
178
179 class wxPipeOutputStream : public wxOutputStream
180 {
181 public:
182 wxPipeOutputStream(NSPipe* thePipe) :
183 m_thePipe(thePipe),
184 m_theHandle([m_thePipe fileHandleForWriting])
185 {
186 }
187
188 ~wxPipeOutputStream()
189 {
190 [m_thePipe release];
191 }
192
193 protected:
194
195 virtual size_t OnSysWrite(const void *buffer, size_t bufsize)
196 {
197 NSData* theData = [NSData dataWithBytesNoCopy:(void*)buffer
198 length:bufsize];
199 [m_theHandle writeData:theData];
200 return bufsize;
201 }
202
203 NSPipe* m_thePipe;
204 NSFileHandle* m_theHandle;
205 };
206
207 @interface wxTaskHandler : NSObject
208 {
209 long m_pid;
210 void* m_handle;
211 }
212 -(id)init:(void*)handle processIdentifier:(long)pid;
213 - (void)termHandler:(NSNotification *)aNotification;
214 @end
215
216 @implementation wxTaskHandler : NSObject
217
218 -(id)init:(void*)handle processIdentifier:(long)pid
219 {
220 self = [super init];
221
222 m_handle = handle;
223 m_pid = pid;
224
225 [[NSNotificationCenter defaultCenter] addObserver:self
226 selector:@selector(termHandler:)
227 name:NSTaskDidTerminateNotification
228 object:nil];
229 return self;
230 }
231
232 - (void)termHandler:(NSNotification *)aNotification
233 {
234 NSTask* theTask = [aNotification object];
235
236 if ([theTask processIdentifier] == m_pid)
237 {
238 ((wxProcess*)m_handle)->OnTerminate([theTask processIdentifier],
239 [theTask terminationStatus]);
240
241 [self release];
242 }
243 }
244
245 @end
246
247 long wxExecute(const wxString& command,
248 int sync,
249 wxProcess *handle)
250 {
251 NSTask* theTask = [[NSTask alloc] init];
252
253 if (handle && handle->IsRedirected())
254 {
255 NSPipe* theStdinPipe = [[NSPipe alloc] init];
256 NSPipe* theStderrPipe = [[NSPipe alloc] init];
257 NSPipe* theStdoutPipe = [[NSPipe alloc] init];
258
259 [theTask setStandardInput:theStdinPipe];
260 [theTask setStandardError:theStderrPipe];
261 [theTask setStandardOutput:theStdoutPipe];
262
263 handle->SetPipeStreams(new wxPipeInputStream(theStdoutPipe),
264 new wxPipeOutputStream(theStdinPipe),
265 new wxPipeInputStream(theStderrPipe) );
266 }
267
268 NSArray* theQuoteArguments =
269 [wxNSStringWithWxString(command) componentsSeparatedByString:@"\""];
270
271 NSMutableArray* theSeperatedArguments =
272 [NSMutableArray arrayWithCapacity:10];
273
274 for (unsigned i = 0; i < [theQuoteArguments count]; ++i)
275 {
276 [theSeperatedArguments addObjectsFromArray:
277 [[theQuoteArguments objectAtIndex:i] componentsSeparatedByString:@" "]
278 ];
279
280 if(++i < [theQuoteArguments count])
281 [theSeperatedArguments addObject:[theQuoteArguments objectAtIndex:i]];
282 }
283
284 [theTask setLaunchPath:[theSeperatedArguments objectAtIndex:0]];
285 [theTask setArguments:theSeperatedArguments];
286 [theTask launch];
287
288 if(sync & wxEXEC_ASYNC)
289 {
290 [[wxTaskHandler alloc]init:handle
291 processIdentifier:[theTask processIdentifier]];
292
293 return 0;
294 }
295 else
296 {
297 [theTask waitUntilExit];
298
299 return [theTask terminationStatus];
300 }
301 }
302
303 */