]> git.saurik.com Git - wxWidgets.git/blame - src/unix/utilsunx.cpp
Correct EnsureVisible() to show last item entirely
[wxWidgets.git] / src / unix / utilsunx.cpp
CommitLineData
518b5d2f 1/////////////////////////////////////////////////////////////////////////////
7520f3da 2// Name: src/unix/utilsunx.cpp
518b5d2f
VZ
3// Purpose: generic Unix implementation of many wx functions
4// Author: Vadim Zeitlin
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin
65571936 7// Licence: wxWindows licence
518b5d2f
VZ
8/////////////////////////////////////////////////////////////////////////////
9
10// ============================================================================
11// declarations
12// ============================================================================
13
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
14f355c2
VS
18// for compilers that support precompilation, includes "wx.h".
19#include "wx/wxprec.h"
20
88a7a4e1
WS
21#include "wx/utils.h"
22
c0472c7c
VZ
23#define USE_PUTENV (!defined(HAVE_SETENV) && defined(HAVE_PUTENV))
24
7520f3da
WS
25#ifndef WX_PRECOMP
26 #include "wx/string.h"
88a7a4e1 27 #include "wx/intl.h"
e4db172a 28 #include "wx/log.h"
670f9935 29 #include "wx/app.h"
0cb7e05c 30 #include "wx/wxcrtvararg.h"
c0472c7c
VZ
31 #if USE_PUTENV
32 #include "wx/module.h"
33 #include "wx/hashmap.h"
34 #endif
7520f3da 35#endif
518b5d2f 36
46446cc2 37#include "wx/apptrait.h"
518b5d2f 38
518b5d2f 39#include "wx/process.h"
bdc72a22 40#include "wx/thread.h"
518b5d2f 41
80d6dc0a 42#include "wx/wfstream.h"
8b33ae2d 43
e2478fde 44#include "wx/unix/execute.h"
17a1ebd1
VZ
45#include "wx/unix/private.h"
46
47#include <pwd.h>
bc855d09 48#include <sys/wait.h> // waitpid()
e2478fde 49
bc023abb
MW
50#ifdef HAVE_SYS_SELECT_H
51# include <sys/select.h>
52#endif
53
1f3b2af0
VS
54#define HAS_PIPE_INPUT_STREAM (wxUSE_STREAMS && wxUSE_FILE)
55
56#if HAS_PIPE_INPUT_STREAM
2887179b
VZ
57
58// define this to let wxexec.cpp know that we know what we're doing
59#define _WX_USED_BY_WXEXECUTE_
60#include "../common/execcmn.cpp"
61
1f3b2af0 62#endif // HAS_PIPE_INPUT_STREAM
2887179b 63
ec67cff1 64#if wxUSE_BASE
e2478fde 65
74c719ed
VZ
66#if defined(__MWERKS__) && defined(__MACH__)
67 #ifndef WXWIN_OS_DESCRIPTION
68 #define WXWIN_OS_DESCRIPTION "MacOS X"
69 #endif
70 #ifndef HAVE_NANOSLEEP
71 #define HAVE_NANOSLEEP
72 #endif
73 #ifndef HAVE_UNAME
74 #define HAVE_UNAME
75 #endif
76
77 // our configure test believes we can use sigaction() if the function is
78 // available but Metrowekrs with MSL run-time does have the function but
79 // doesn't have sigaction struct so finally we can't use it...
80 #ifdef __MSL__
81 #undef wxUSE_ON_FATAL_EXCEPTION
82 #define wxUSE_ON_FATAL_EXCEPTION 0
83 #endif
8d4f85ce
SC
84#endif
85
85da04e9
VZ
86// not only the statfs syscall is called differently depending on platform, but
87// one of its incarnations, statvfs(), takes different arguments under
88// different platforms and even different versions of the same system (Solaris
89// 7 and 8): if you want to test for this, don't forget that the problems only
90// appear if the large files support is enabled
eadd7bd2 91#ifdef HAVE_STATFS
85da04e9
VZ
92 #ifdef __BSD__
93 #include <sys/param.h>
94 #include <sys/mount.h>
95 #else // !__BSD__
96 #include <sys/vfs.h>
97 #endif // __BSD__/!__BSD__
98
99 #define wxStatfs statfs
84ae7ca4
VZ
100
101 #ifndef HAVE_STATFS_DECL
102 // some systems lack statfs() prototype in the system headers (AIX 4)
103 extern "C" int statfs(const char *path, struct statfs *buf);
104 #endif
eadd7bd2
VZ
105#endif // HAVE_STATFS
106
9952adac
VZ
107#ifdef HAVE_STATVFS
108 #include <sys/statvfs.h>
109
85da04e9
VZ
110 #define wxStatfs statvfs
111#endif // HAVE_STATVFS
112
113#if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
114 // WX_STATFS_T is detected by configure
115 #define wxStatfs_t WX_STATFS_T
116#endif
9952adac 117
f6bcfd97
BP
118// SGI signal.h defines signal handler arguments differently depending on
119// whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it
120#if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS)
121 #define _LANGUAGE_C_PLUS_PLUS 1
122#endif // SGI hack
123
518b5d2f
VZ
124#include <stdarg.h>
125#include <dirent.h>
126#include <string.h>
127#include <sys/stat.h>
128#include <sys/types.h>
518b5d2f 129#include <sys/wait.h>
e2478fde 130#include <unistd.h>
518b5d2f
VZ
131#include <errno.h>
132#include <netdb.h>
133#include <signal.h>
134#include <fcntl.h> // for O_WRONLY and friends
135#include <time.h> // nanosleep() and/or usleep()
fad866f4 136#include <ctype.h> // isspace()
b12915c1 137#include <sys/time.h> // needed for FD_SETSIZE
7bcb11d3 138
0fcdf6dc 139#ifdef HAVE_UNAME
518b5d2f
VZ
140 #include <sys/utsname.h> // for uname()
141#endif // HAVE_UNAME
142
9ad34f61
VZ
143// Used by wxGetFreeMemory().
144#ifdef __SGI__
145 #include <sys/sysmp.h>
146 #include <sys/sysinfo.h> // for SAGET and MINFO structures
147#endif
148
518b5d2f
VZ
149// ----------------------------------------------------------------------------
150// conditional compilation
151// ----------------------------------------------------------------------------
152
153// many versions of Unices have this function, but it is not defined in system
154// headers - please add your system here if it is the case for your OS.
155// SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
1363811b 156#if !defined(HAVE_USLEEP) && \
d67fee71 157 ((defined(__SUN__) && !defined(__SunOs_5_6) && \
518b5d2f 158 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
d67fee71 159 defined(__osf__) || defined(__EMX__))
518b5d2f
VZ
160 extern "C"
161 {
1a5e269b
VZ
162 #ifdef __EMX__
163 /* I copied this from the XFree86 diffs. AV. */
164 #define INCL_DOSPROCESS
165 #include <os2.h>
166 inline void usleep(unsigned long delay)
167 {
168 DosSleep(delay ? (delay/1000l) : 1l);
169 }
170 #else // Unix
1363811b 171 int usleep(unsigned int usec);
1a5e269b 172 #endif // __EMX__/Unix
518b5d2f 173 };
bdc72a22
VZ
174
175 #define HAVE_USLEEP 1
518b5d2f
VZ
176#endif // Unices without usleep()
177
518b5d2f
VZ
178// ============================================================================
179// implementation
180// ============================================================================
181
182// ----------------------------------------------------------------------------
183// sleeping
184// ----------------------------------------------------------------------------
185
186void wxSleep(int nSecs)
187{
188 sleep(nSecs);
189}
190
66cd9d7f 191void wxMicroSleep(unsigned long microseconds)
518b5d2f 192{
b12915c1 193#if defined(HAVE_NANOSLEEP)
518b5d2f 194 timespec tmReq;
66cd9d7f
VZ
195 tmReq.tv_sec = (time_t)(microseconds / 1000000);
196 tmReq.tv_nsec = (microseconds % 1000000) * 1000;
518b5d2f
VZ
197
198 // we're not interested in remaining time nor in return value
199 (void)nanosleep(&tmReq, (timespec *)NULL);
b12915c1 200#elif defined(HAVE_USLEEP)
518b5d2f
VZ
201 // uncomment this if you feel brave or if you are sure that your version
202 // of Solaris has a safe usleep() function but please notice that usleep()
203 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
204 // documented as MT-Safe
ea18eed9 205 #if defined(__SUN__) && wxUSE_THREADS
518b5d2f
VZ
206 #error "usleep() cannot be used in MT programs under Solaris."
207 #endif // Sun
208
66cd9d7f 209 usleep(microseconds);
b12915c1
VZ
210#elif defined(HAVE_SLEEP)
211 // under BeOS sleep() takes seconds (what about other platforms, if any?)
66cd9d7f 212 sleep(microseconds * 1000000);
518b5d2f 213#else // !sleep function
66cd9d7f 214 #error "usleep() or nanosleep() function required for wxMicroSleep"
518b5d2f
VZ
215#endif // sleep function
216}
217
66cd9d7f
VZ
218void wxMilliSleep(unsigned long milliseconds)
219{
220 wxMicroSleep(milliseconds*1000);
221}
222
518b5d2f
VZ
223// ----------------------------------------------------------------------------
224// process management
225// ----------------------------------------------------------------------------
226
e0f6b731 227int wxKill(long pid, wxSignal sig, wxKillError *rc, int flags)
518b5d2f 228{
e0f6b731 229 int err = kill((pid_t) (flags & wxKILL_CHILDREN) ? -pid : pid, (int)sig);
50567b69
VZ
230 if ( rc )
231 {
f0bce4d4 232 switch ( err ? errno : 0 )
50567b69
VZ
233 {
234 case 0:
235 *rc = wxKILL_OK;
236 break;
237
238 case EINVAL:
239 *rc = wxKILL_BAD_SIGNAL;
240 break;
241
242 case EPERM:
243 *rc = wxKILL_ACCESS_DENIED;
244 break;
245
246 case ESRCH:
247 *rc = wxKILL_NO_PROCESS;
248 break;
249
250 default:
251 // this goes against Unix98 docs so log it
252 wxLogDebug(_T("unexpected kill(2) return value %d"), err);
253
254 // something else...
255 *rc = wxKILL_ERROR;
256 }
257 }
258
259 return err;
518b5d2f
VZ
260}
261
fad866f4
KB
262#define WXEXECUTE_NARGS 127
263
62705a27
RN
264#if defined(__DARWIN__)
265long wxMacExecute(wxChar **argv,
266 int flags,
267 wxProcess *process);
268#endif
269
fbf456aa 270long wxExecute( const wxString& command, int flags, wxProcess *process )
518b5d2f 271{
8ea92b4d 272 wxCHECK_MSG( !command.empty(), 0, wxT("can't exec empty command") );
ba2eff22
VZ
273
274 wxLogTrace(wxT("exec"), wxT("Executing \"%s\""), command.c_str());
518b5d2f 275
647b8e37
VZ
276#if wxUSE_THREADS
277 // fork() doesn't mix well with POSIX threads: on many systems the program
278 // deadlocks or crashes for some reason. Probably our code is buggy and
279 // doesn't do something which must be done to allow this to work, but I
280 // don't know what yet, so for now just warn the user (this is the least we
281 // can do) about it
282 wxASSERT_MSG( wxThread::IsMain(),
283 _T("wxExecute() can be called only from the main thread") );
284#endif // wxUSE_THREADS
285
518b5d2f 286 int argc = 0;
05079acc 287 wxChar *argv[WXEXECUTE_NARGS];
fad866f4 288 wxString argument;
05079acc 289 const wxChar *cptr = command.c_str();
223d09f6 290 wxChar quotechar = wxT('\0'); // is arg quoted?
9d8aca48 291 bool escaped = false;
518b5d2f 292
0ed9a934 293 // split the command line in arguments
fad866f4
KB
294 do
295 {
7520f3da 296 argument = wxEmptyString;
223d09f6 297 quotechar = wxT('\0');
0ed9a934 298
fad866f4 299 // eat leading whitespace:
05079acc 300 while ( wxIsspace(*cptr) )
fad866f4 301 cptr++;
0ed9a934 302
223d09f6 303 if ( *cptr == wxT('\'') || *cptr == wxT('"') )
fad866f4 304 quotechar = *cptr++;
0ed9a934 305
fad866f4
KB
306 do
307 {
223d09f6 308 if ( *cptr == wxT('\\') && ! escaped )
fad866f4 309 {
9d8aca48 310 escaped = true;
fad866f4
KB
311 cptr++;
312 continue;
313 }
0ed9a934 314
fad866f4 315 // all other characters:
0ed9a934 316 argument += *cptr++;
9d8aca48 317 escaped = false;
0ed9a934
VZ
318
319 // have we reached the end of the argument?
320 if ( (*cptr == quotechar && ! escaped)
223d09f6
KB
321 || (quotechar == wxT('\0') && wxIsspace(*cptr))
322 || *cptr == wxT('\0') )
fad866f4 323 {
0ed9a934 324 wxASSERT_MSG( argc < WXEXECUTE_NARGS,
223d09f6 325 wxT("too many arguments in wxExecute") );
0ed9a934 326
05079acc
OK
327 argv[argc] = new wxChar[argument.length() + 1];
328 wxStrcpy(argv[argc], argument.c_str());
fad866f4 329 argc++;
0ed9a934 330
fad866f4 331 // if not at end of buffer, swallow last character:
0ed9a934
VZ
332 if(*cptr)
333 cptr++;
334
fad866f4
KB
335 break; // done with this one, start over
336 }
0ed9a934
VZ
337 } while(*cptr);
338 } while(*cptr);
fad866f4 339 argv[argc] = NULL;
0ed9a934 340
62705a27
RN
341 long lRc;
342#if defined(__DARWIN__)
3afdfec4 343 // wxMacExecute only executes app bundles.
fb19fbab
SC
344 // It returns an error code if the target is not an app bundle, thus falling
345 // through to the regular wxExecute for non app bundles.
3afdfec4 346 lRc = wxMacExecute(argv, flags, process);
fb19fbab 347 if( lRc != ((flags & wxEXEC_SYNC) ? -1 : 0))
62705a27
RN
348 return lRc;
349#endif
350
0ed9a934 351 // do execute the command
62705a27 352 lRc = wxExecute(argv, flags, process);
518b5d2f 353
0ed9a934 354 // clean up
fad866f4 355 argc = 0;
0ed9a934 356 while( argv[argc] )
fad866f4 357 delete [] argv[argc++];
518b5d2f
VZ
358
359 return lRc;
360}
361
2c8e4738
VZ
362// ----------------------------------------------------------------------------
363// wxShell
364// ----------------------------------------------------------------------------
365
366static wxString wxMakeShellCommand(const wxString& command)
518b5d2f
VZ
367{
368 wxString cmd;
cd6ce4a9 369 if ( !command )
2c8e4738
VZ
370 {
371 // just an interactive shell
cd6ce4a9 372 cmd = _T("xterm");
2c8e4738 373 }
518b5d2f 374 else
2c8e4738
VZ
375 {
376 // execute command in a shell
377 cmd << _T("/bin/sh -c '") << command << _T('\'');
378 }
379
380 return cmd;
381}
382
383bool wxShell(const wxString& command)
384{
fbf456aa 385 return wxExecute(wxMakeShellCommand(command), wxEXEC_SYNC) == 0;
2c8e4738
VZ
386}
387
388bool wxShell(const wxString& command, wxArrayString& output)
389{
9d8aca48 390 wxCHECK_MSG( !command.empty(), false, _T("can't exec shell non interactively") );
518b5d2f 391
2c8e4738 392 return wxExecute(wxMakeShellCommand(command), output);
518b5d2f
VZ
393}
394
f6ba47d9
VZ
395// Shutdown or reboot the PC
396bool wxShutdown(wxShutdownFlags wFlags)
397{
398 wxChar level;
399 switch ( wFlags )
400 {
401 case wxSHUTDOWN_POWEROFF:
402 level = _T('0');
403 break;
404
405 case wxSHUTDOWN_REBOOT:
406 level = _T('6');
407 break;
408
409 default:
410 wxFAIL_MSG( _T("unknown wxShutdown() flag") );
9d8aca48 411 return false;
f6ba47d9
VZ
412 }
413
414 return system(wxString::Format(_T("init %c"), level).mb_str()) == 0;
415}
416
cd6ce4a9
VZ
417// ----------------------------------------------------------------------------
418// wxStream classes to support IO redirection in wxExecute
419// ----------------------------------------------------------------------------
6dc6fda6 420
1f3b2af0 421#if HAS_PIPE_INPUT_STREAM
1e6feb95 422
2b5f62a0 423bool wxPipeInputStream::CanRead() const
8b33ae2d 424{
cd6ce4a9 425 if ( m_lasterror == wxSTREAM_EOF )
9d8aca48 426 return false;
cd6ce4a9
VZ
427
428 // check if there is any input available
429 struct timeval tv;
430 tv.tv_sec = 0;
431 tv.tv_usec = 0;
432
80d6dc0a
VZ
433 const int fd = m_file->fd();
434
cd6ce4a9 435 fd_set readfds;
17a1ebd1
VZ
436
437 wxFD_ZERO(&readfds);
438 wxFD_SET(fd, &readfds);
439
80d6dc0a 440 switch ( select(fd + 1, &readfds, NULL, NULL, &tv) )
cd6ce4a9
VZ
441 {
442 case -1:
443 wxLogSysError(_("Impossible to get child process input"));
444 // fall through
8b33ae2d 445
cd6ce4a9 446 case 0:
9d8aca48 447 return false;
8b33ae2d 448
cd6ce4a9
VZ
449 default:
450 wxFAIL_MSG(_T("unexpected select() return value"));
451 // still fall through
452
453 case 1:
6f3d3c68
VZ
454 // input available -- or maybe not, as select() returns 1 when a
455 // read() will complete without delay, but it could still not read
456 // anything
457 return !Eof();
cd6ce4a9 458 }
8b33ae2d
GL
459}
460
1f3b2af0 461#endif // HAS_PIPE_INPUT_STREAM
1e6feb95 462
b477f956
VZ
463// ----------------------------------------------------------------------------
464// wxExecute: the real worker function
465// ----------------------------------------------------------------------------
79066131 466
17a1ebd1 467long wxExecute(wxChar **argv, int flags, wxProcess *process)
518b5d2f 468{
f6bcfd97 469 // for the sync execution, we return -1 to indicate failure, but for async
accb3257
VZ
470 // case we return 0 which is never a valid PID
471 //
472 // we define this as a macro, not a variable, to avoid compiler warnings
473 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
fbf456aa 474 #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)
f6bcfd97 475
accb3257 476 wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") );
518b5d2f 477
05079acc
OK
478#if wxUSE_UNICODE
479 int mb_argc = 0;
480 char *mb_argv[WXEXECUTE_NARGS];
481
e90c1d2a
VZ
482 while (argv[mb_argc])
483 {
69c928ef 484 wxWX2MBbuf mb_arg = wxSafeConvertWX2MB(argv[mb_argc]);
cd6ce4a9
VZ
485 mb_argv[mb_argc] = strdup(mb_arg);
486 mb_argc++;
05079acc
OK
487 }
488 mb_argv[mb_argc] = (char *) NULL;
e90c1d2a
VZ
489
490 // this macro will free memory we used above
491 #define ARGS_CLEANUP \
345b0247 492 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
e90c1d2a
VZ
493 free(mb_argv[mb_argc])
494#else // ANSI
495 // no need for cleanup
496 #define ARGS_CLEANUP
497
05079acc 498 wxChar **mb_argv = argv;
e90c1d2a 499#endif // Unicode/ANSI
518b5d2f 500
e2478fde
VZ
501 // we want this function to work even if there is no wxApp so ensure that
502 // we have a valid traits pointer
503 wxConsoleAppTraits traitsConsole;
504 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
505 if ( !traits )
506 traits = &traitsConsole;
507
508 // this struct contains all information which we pass to and from
509 // wxAppTraits methods
510 wxExecuteData execData;
511 execData.flags = flags;
512 execData.process = process;
513
518b5d2f 514 // create pipes
e2478fde 515 if ( !traits->CreateEndProcessPipe(execData) )
518b5d2f 516 {
cd6ce4a9 517 wxLogError( _("Failed to execute '%s'\n"), *argv );
e90c1d2a
VZ
518
519 ARGS_CLEANUP;
520
accb3257 521 return ERROR_RETURN_CODE;
518b5d2f
VZ
522 }
523
f6bcfd97 524 // pipes for inter process communication
b477f956
VZ
525 wxPipe pipeIn, // stdin
526 pipeOut, // stdout
527 pipeErr; // stderr
cd6ce4a9
VZ
528
529 if ( process && process->IsRedirected() )
8b33ae2d 530 {
b477f956 531 if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
8b33ae2d 532 {
cd6ce4a9 533 wxLogError( _("Failed to execute '%s'\n"), *argv );
8b33ae2d
GL
534
535 ARGS_CLEANUP;
536
accb3257 537 return ERROR_RETURN_CODE;
8b33ae2d
GL
538 }
539 }
8b33ae2d 540
518b5d2f 541 // fork the process
ef5f8ab6
VZ
542 //
543 // NB: do *not* use vfork() here, it completely breaks this code for some
544 // reason under Solaris (and maybe others, although not under Linux)
b2ddee86
JJ
545 // But on OpenVMS we do not have fork so we have to use vfork and
546 // cross our fingers that it works.
547#ifdef __VMS
548 pid_t pid = vfork();
549#else
550 pid_t pid = fork();
551#endif
552 if ( pid == -1 ) // error?
518b5d2f
VZ
553 {
554 wxLogSysError( _("Fork failed") );
e90c1d2a
VZ
555
556 ARGS_CLEANUP;
557
accb3257 558 return ERROR_RETURN_CODE;
518b5d2f 559 }
cd6ce4a9 560 else if ( pid == 0 ) // we're in child
518b5d2f 561 {
cd6ce4a9 562 // These lines close the open file descriptors to to avoid any
518b5d2f 563 // input/output which might block the process or irritate the user. If
cd6ce4a9
VZ
564 // one wants proper IO for the subprocess, the right thing to do is to
565 // start an xterm executing it.
fbf456aa 566 if ( !(flags & wxEXEC_SYNC) )
518b5d2f 567 {
35ef537b
VZ
568 // FD_SETSIZE is unsigned under BSD, signed under other platforms
569 // so we need a cast to avoid warnings on all platforms
570 for ( int fd = 0; fd < (int)FD_SETSIZE; fd++ )
518b5d2f 571 {
b477f956
VZ
572 if ( fd == pipeIn[wxPipe::Read]
573 || fd == pipeOut[wxPipe::Write]
574 || fd == pipeErr[wxPipe::Write]
e2478fde 575 || traits->IsWriteFDOfEndProcessPipe(execData, fd) )
cd6ce4a9
VZ
576 {
577 // don't close this one, we still need it
578 continue;
579 }
e90c1d2a 580
b477f956 581 // leave stderr opened too, it won't do any harm
e90c1d2a 582 if ( fd != STDERR_FILENO )
518b5d2f
VZ
583 close(fd);
584 }
0c9c4401 585 }
e1082c9f 586
e8e776aa 587#if !defined(__VMS) && !defined(__EMX__)
0c9c4401
VZ
588 if ( flags & wxEXEC_MAKE_GROUP_LEADER )
589 {
590 // Set process group to child process' pid. Then killing -pid
591 // of the parent will kill the process and all of its children.
592 setsid();
518b5d2f 593 }
0c9c4401
VZ
594#endif // !__VMS
595
0c9c4401
VZ
596 // reading side can be safely closed but we should keep the write one
597 // opened
e2478fde 598 traits->DetachWriteFDOfEndProcessPipe(execData);
518b5d2f 599
80d6dc0a 600 // redirect stdin, stdout and stderr
b477f956 601 if ( pipeIn.IsOk() )
cd6ce4a9 602 {
b477f956
VZ
603 if ( dup2(pipeIn[wxPipe::Read], STDIN_FILENO) == -1 ||
604 dup2(pipeOut[wxPipe::Write], STDOUT_FILENO) == -1 ||
605 dup2(pipeErr[wxPipe::Write], STDERR_FILENO) == -1 )
cd6ce4a9 606 {
f6bcfd97 607 wxLogSysError(_("Failed to redirect child process input/output"));
cd6ce4a9 608 }
518b5d2f 609
b477f956
VZ
610 pipeIn.Close();
611 pipeOut.Close();
612 pipeErr.Close();
cd6ce4a9 613 }
518b5d2f 614
05079acc 615 execvp (*mb_argv, mb_argv);
17a1ebd1 616
d264d709 617 fprintf(stderr, "execvp(");
8d4f85ce
SC
618 // CS changed ppc to ppc_ as ppc is not available under mac os CW Mach-O
619 for ( char **ppc_ = mb_argv; *ppc_; ppc_++ )
620 fprintf(stderr, "%s%s", ppc_ == mb_argv ? "" : ", ", *ppc_);
d264d709
VZ
621 fprintf(stderr, ") failed with error %d!\n", errno);
622
518b5d2f 623 // there is no return after successful exec()
518b5d2f 624 _exit(-1);
1d8dd65e
VZ
625
626 // some compilers complain about missing return - of course, they
627 // should know that exit() doesn't return but what else can we do if
628 // they don't?
b477f956
VZ
629 //
630 // and, sure enough, other compilers complain about unreachable code
631 // after exit() call, so we can just always have return here...
1d8dd65e
VZ
632#if defined(__VMS) || defined(__INTEL_COMPILER)
633 return 0;
634#endif
518b5d2f 635 }
cd6ce4a9 636 else // we're in parent
518b5d2f 637 {
cd6ce4a9
VZ
638 ARGS_CLEANUP;
639
7764f973
VZ
640 // save it for WaitForChild() use
641 execData.pid = pid;
642
80d6dc0a
VZ
643 // prepare for IO redirection
644
1f3b2af0 645#if HAS_PIPE_INPUT_STREAM
80d6dc0a
VZ
646 // the input buffer bufOut is connected to stdout, this is why it is
647 // called bufOut and not bufIn
648 wxStreamTempInputBuffer bufOut,
649 bufErr;
1f3b2af0 650#endif // HAS_PIPE_INPUT_STREAM
0e300ddd 651
cd6ce4a9
VZ
652 if ( process && process->IsRedirected() )
653 {
1f3b2af0 654#if HAS_PIPE_INPUT_STREAM
80d6dc0a
VZ
655 wxOutputStream *inStream =
656 new wxFileOutputStream(pipeIn.Detach(wxPipe::Write));
b477f956 657
79066131
VZ
658 wxPipeInputStream *outStream =
659 new wxPipeInputStream(pipeOut.Detach(wxPipe::Read));
b477f956 660
79066131
VZ
661 wxPipeInputStream *errStream =
662 new wxPipeInputStream(pipeErr.Detach(wxPipe::Read));
f6bcfd97 663
80d6dc0a 664 process->SetPipeStreams(outStream, inStream, errStream);
0e300ddd 665
80d6dc0a 666 bufOut.Init(outStream);
b477f956 667 bufErr.Init(errStream);
e2478fde
VZ
668
669 execData.bufOut = &bufOut;
670 execData.bufErr = &bufErr;
1f3b2af0 671#endif // HAS_PIPE_INPUT_STREAM
b477f956 672 }
1e6feb95 673
b477f956
VZ
674 if ( pipeIn.IsOk() )
675 {
676 pipeIn.Close();
677 pipeOut.Close();
678 pipeErr.Close();
cd6ce4a9
VZ
679 }
680
e2478fde 681 return traits->WaitForChild(execData);
518b5d2f 682 }
79656e30 683
17a1ebd1 684#if !defined(__VMS) && !defined(__INTEL_COMPILER)
79656e30 685 return ERROR_RETURN_CODE;
ef0ed19e 686#endif
17a1ebd1 687}
518b5d2f 688
accb3257 689#undef ERROR_RETURN_CODE
f6bcfd97
BP
690#undef ARGS_CLEANUP
691
518b5d2f
VZ
692// ----------------------------------------------------------------------------
693// file and directory functions
694// ----------------------------------------------------------------------------
695
05079acc 696const wxChar* wxGetHomeDir( wxString *home )
518b5d2f 697{
14d63513 698 *home = wxGetUserHome();
79066131 699 wxString tmp;
8ea92b4d 700 if ( home->empty() )
223d09f6 701 *home = wxT("/");
181cbcf4 702#ifdef __VMS
79066131
VZ
703 tmp = *home;
704 if ( tmp.Last() != wxT(']'))
705 if ( tmp.Last() != wxT('/')) *home << wxT('/');
181cbcf4 706#endif
518b5d2f
VZ
707 return home->c_str();
708}
709
14d63513 710wxString wxGetUserHome( const wxString &user )
518b5d2f
VZ
711{
712 struct passwd *who = (struct passwd *) NULL;
713
0fb67cd1 714 if ( !user )
518b5d2f 715 {
e90c1d2a 716 wxChar *ptr;
518b5d2f 717
223d09f6 718 if ((ptr = wxGetenv(wxT("HOME"))) != NULL)
518b5d2f
VZ
719 {
720 return ptr;
721 }
14d63513
VZ
722
723 if ((ptr = wxGetenv(wxT("USER"))) != NULL ||
724 (ptr = wxGetenv(wxT("LOGNAME"))) != NULL)
518b5d2f 725 {
69c928ef 726 who = getpwnam(wxSafeConvertWX2MB(ptr));
518b5d2f
VZ
727 }
728
14d63513
VZ
729 // make sure the user exists!
730 if ( !who )
518b5d2f
VZ
731 {
732 who = getpwuid(getuid());
733 }
734 }
735 else
736 {
05079acc 737 who = getpwnam (user.mb_str());
518b5d2f
VZ
738 }
739
69c928ef 740 return wxSafeConvertMB2WX(who ? who->pw_dir : 0);
518b5d2f
VZ
741}
742
743// ----------------------------------------------------------------------------
0fb67cd1 744// network and user id routines
518b5d2f
VZ
745// ----------------------------------------------------------------------------
746
8bb6b2c0
VZ
747// private utility function which returns output of the given command, removing
748// the trailing newline
749static wxString wxGetCommandOutput(const wxString &cmd)
750{
751 FILE *f = popen(cmd.ToAscii(), "r");
752 if ( !f )
753 {
754 wxLogSysError(_T("Executing \"%s\" failed"), cmd.c_str());
755 return wxEmptyString;
756 }
757
758 wxString s;
759 char buf[256];
760 while ( !feof(f) )
761 {
762 if ( !fgets(buf, sizeof(buf), f) )
763 break;
764
765 s += wxString::FromAscii(buf);
766 }
767
768 pclose(f);
769
770 if ( !s.empty() && s.Last() == _T('\n') )
771 s.RemoveLast();
772
773 return s;
774}
775
0fb67cd1
VZ
776// retrieve either the hostname or FQDN depending on platform (caller must
777// check whether it's one or the other, this is why this function is for
778// private use only)
05079acc 779static bool wxGetHostNameInternal(wxChar *buf, int sz)
518b5d2f 780{
9d8aca48 781 wxCHECK_MSG( buf, false, wxT("NULL pointer in wxGetHostNameInternal") );
518b5d2f 782
223d09f6 783 *buf = wxT('\0');
518b5d2f
VZ
784
785 // we're using uname() which is POSIX instead of less standard sysinfo()
786#if defined(HAVE_UNAME)
cc743a6f 787 struct utsname uts;
518b5d2f
VZ
788 bool ok = uname(&uts) != -1;
789 if ( ok )
790 {
69c928ef 791 wxStrncpy(buf, wxSafeConvertMB2WX(uts.nodename), sz - 1);
223d09f6 792 buf[sz] = wxT('\0');
518b5d2f
VZ
793 }
794#elif defined(HAVE_GETHOSTNAME)
1870f50b
RD
795 char cbuf[sz];
796 bool ok = gethostname(cbuf, sz) != -1;
797 if ( ok )
798 {
69c928ef 799 wxStrncpy(buf, wxSafeConvertMB2WX(cbuf), sz - 1);
1870f50b
RD
800 buf[sz] = wxT('\0');
801 }
0fb67cd1 802#else // no uname, no gethostname
223d09f6 803 wxFAIL_MSG(wxT("don't know host name for this machine"));
518b5d2f 804
9d8aca48 805 bool ok = false;
0fb67cd1 806#endif // uname/gethostname
518b5d2f
VZ
807
808 if ( !ok )
809 {
810 wxLogSysError(_("Cannot get the hostname"));
811 }
812
813 return ok;
814}
815
05079acc 816bool wxGetHostName(wxChar *buf, int sz)
0fb67cd1
VZ
817{
818 bool ok = wxGetHostNameInternal(buf, sz);
819
820 if ( ok )
821 {
822 // BSD systems return the FQDN, we only want the hostname, so extract
823 // it (we consider that dots are domain separators)
223d09f6 824 wxChar *dot = wxStrchr(buf, wxT('.'));
0fb67cd1
VZ
825 if ( dot )
826 {
827 // nuke it
223d09f6 828 *dot = wxT('\0');
0fb67cd1
VZ
829 }
830 }
831
832 return ok;
833}
834
05079acc 835bool wxGetFullHostName(wxChar *buf, int sz)
0fb67cd1
VZ
836{
837 bool ok = wxGetHostNameInternal(buf, sz);
838
839 if ( ok )
840 {
223d09f6 841 if ( !wxStrchr(buf, wxT('.')) )
0fb67cd1 842 {
69c928ef 843 struct hostent *host = gethostbyname(wxSafeConvertWX2MB(buf));
0fb67cd1
VZ
844 if ( !host )
845 {
846 wxLogSysError(_("Cannot get the official hostname"));
847
9d8aca48 848 ok = false;
0fb67cd1
VZ
849 }
850 else
851 {
852 // the canonical name
69c928ef 853 wxStrncpy(buf, wxSafeConvertMB2WX(host->h_name), sz);
0fb67cd1
VZ
854 }
855 }
856 //else: it's already a FQDN (BSD behaves this way)
857 }
858
859 return ok;
860}
861
05079acc 862bool wxGetUserId(wxChar *buf, int sz)
518b5d2f
VZ
863{
864 struct passwd *who;
865
223d09f6 866 *buf = wxT('\0');
518b5d2f
VZ
867 if ((who = getpwuid(getuid ())) != NULL)
868 {
69c928ef 869 wxStrncpy (buf, wxSafeConvertMB2WX(who->pw_name), sz - 1);
9d8aca48 870 return true;
518b5d2f
VZ
871 }
872
9d8aca48 873 return false;
518b5d2f
VZ
874}
875
05079acc 876bool wxGetUserName(wxChar *buf, int sz)
518b5d2f 877{
69c928ef 878#ifdef HAVE_PW_GECOS
518b5d2f 879 struct passwd *who;
518b5d2f 880
223d09f6 881 *buf = wxT('\0');
b12915c1
VZ
882 if ((who = getpwuid (getuid ())) != NULL)
883 {
b12915c1 884 char *comma = strchr(who->pw_gecos, ',');
518b5d2f
VZ
885 if (comma)
886 *comma = '\0'; // cut off non-name comment fields
69c928ef 887 wxStrncpy (buf, wxSafeConvertMB2WX(who->pw_gecos), sz - 1);
9d8aca48 888 return true;
518b5d2f
VZ
889 }
890
9d8aca48 891 return false;
69c928ef
VZ
892#else // !HAVE_PW_GECOS
893 return wxGetUserId(buf, sz);
894#endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
518b5d2f
VZ
895}
896
c655557f
VZ
897bool wxIsPlatform64Bit()
898{
2f6aa043
VZ
899 const wxString machine = wxGetCommandOutput(wxT("uname -m"));
900
901 // the test for "64" is obviously not 100% reliable but seems to work fine
902 // in practice
903 return machine.Contains(wxT("64")) ||
904 machine.Contains(wxT("alpha"));
c655557f
VZ
905}
906
907// these functions are in mac/utils.cpp for wxMac
908#ifndef __WXMAC__
909
8bb6b2c0
VZ
910wxOperatingSystemId wxGetOsVersion(int *verMaj, int *verMin)
911{
912 // get OS version
913 int major, minor;
914 wxString release = wxGetCommandOutput(wxT("uname -r"));
86501081
VS
915 if ( release.empty() ||
916 wxSscanf(release.c_str(), wxT("%d.%d"), &major, &minor) != 2 )
8bb6b2c0 917 {
e1379e29 918 // failed to get version string or unrecognized format
8bb6b2c0
VZ
919 major =
920 minor = -1;
921 }
922
923 if ( verMaj )
924 *verMaj = major;
925 if ( verMin )
926 *verMin = minor;
927
928 // try to understand which OS are we running
929 wxString kernel = wxGetCommandOutput(wxT("uname -s"));
930 if ( kernel.empty() )
931 kernel = wxGetCommandOutput(wxT("uname -o"));
932
933 if ( kernel.empty() )
934 return wxOS_UNKNOWN;
935
936 return wxPlatformInfo::GetOperatingSystemId(kernel);
937}
938
bdc72a22
VZ
939wxString wxGetOsDescription()
940{
8bb6b2c0 941 return wxGetCommandOutput(wxT("uname -s -r -m"));
bdc72a22
VZ
942}
943
e2478fde 944#endif // !__WXMAC__
bd3277fe 945
c1cb4153
VZ
946unsigned long wxGetProcessId()
947{
948 return (unsigned long)getpid();
949}
950
9d8aca48 951wxMemorySize wxGetFreeMemory()
bd3277fe
VZ
952{
953#if defined(__LINUX__)
954 // get it from /proc/meminfo
955 FILE *fp = fopen("/proc/meminfo", "r");
956 if ( fp )
957 {
958 long memFree = -1;
959
960 char buf[1024];
961 if ( fgets(buf, WXSIZEOF(buf), fp) && fgets(buf, WXSIZEOF(buf), fp) )
962 {
7c28d921
VZ
963 // /proc/meminfo changed its format in kernel 2.6
964 if ( wxPlatformInfo().CheckOSVersion(2, 6) )
965 {
966 unsigned long cached, buffers;
967 sscanf(buf, "MemFree: %ld", &memFree);
968
969 fgets(buf, WXSIZEOF(buf), fp);
970 sscanf(buf, "Buffers: %lu", &buffers);
971
972 fgets(buf, WXSIZEOF(buf), fp);
973 sscanf(buf, "Cached: %lu", &cached);
974
975 // add to "MemFree" also the "Buffers" and "Cached" values as
976 // free(1) does as otherwise the value never makes sense: for
977 // kernel 2.6 it's always almost 0
978 memFree += buffers + cached;
979
980 // values here are always expressed in kB and we want bytes
981 memFree *= 1024;
982 }
983 else // Linux 2.4 (or < 2.6, anyhow)
984 {
985 long memTotal, memUsed;
986 sscanf(buf, "Mem: %ld %ld %ld", &memTotal, &memUsed, &memFree);
987 }
bd3277fe
VZ
988 }
989
990 fclose(fp);
991
9d8aca48 992 return (wxMemorySize)memFree;
bd3277fe 993 }
9ad34f61
VZ
994#elif defined(__SGI__)
995 struct rminfo realmem;
996 if ( sysmp(MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0 )
997 return ((wxMemorySize)realmem.physmem * sysconf(_SC_PAGESIZE));
40f00746
VZ
998#elif defined(_SC_AVPHYS_PAGES)
999 return ((wxMemorySize)sysconf(_SC_AVPHYS_PAGES))*sysconf(_SC_PAGESIZE);
bd3277fe
VZ
1000//#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1001#endif
1002
1003 // can't find it out
1004 return -1;
1005}
1006
7ba7c4e6 1007bool wxGetDiskSpace(const wxString& path, wxDiskspaceSize_t *pTotal, wxDiskspaceSize_t *pFree)
eadd7bd2 1008{
9952adac 1009#if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
fbfb3fb3 1010 // the case to "char *" is needed for AIX 4.3
85da04e9
VZ
1011 wxStatfs_t fs;
1012 if ( wxStatfs((char *)(const char*)path.fn_str(), &fs) != 0 )
eadd7bd2 1013 {
401eb3de 1014 wxLogSysError( wxT("Failed to get file system statistics") );
eadd7bd2 1015
9d8aca48 1016 return false;
eadd7bd2
VZ
1017 }
1018
125cb99b
VZ
1019 // under Solaris we also have to use f_frsize field instead of f_bsize
1020 // which is in general a multiple of f_frsize
1021#ifdef HAVE_STATVFS
7ba7c4e6 1022 wxDiskspaceSize_t blockSize = fs.f_frsize;
125cb99b 1023#else // HAVE_STATFS
7ba7c4e6 1024 wxDiskspaceSize_t blockSize = fs.f_bsize;
125cb99b 1025#endif // HAVE_STATVFS/HAVE_STATFS
9952adac 1026
eadd7bd2
VZ
1027 if ( pTotal )
1028 {
7ba7c4e6 1029 *pTotal = wxDiskspaceSize_t(fs.f_blocks) * blockSize;
eadd7bd2
VZ
1030 }
1031
1032 if ( pFree )
1033 {
7ba7c4e6 1034 *pFree = wxDiskspaceSize_t(fs.f_bavail) * blockSize;
eadd7bd2
VZ
1035 }
1036
9d8aca48 1037 return true;
125cb99b 1038#else // !HAVE_STATFS && !HAVE_STATVFS
9d8aca48 1039 return false;
125cb99b 1040#endif // HAVE_STATFS
eadd7bd2
VZ
1041}
1042
8fd0d89b
VZ
1043// ----------------------------------------------------------------------------
1044// env vars
1045// ----------------------------------------------------------------------------
1046
c0472c7c
VZ
1047#if USE_PUTENV
1048
1049WX_DECLARE_STRING_HASH_MAP(char *, wxEnvVars);
1050
1051static wxEnvVars gs_envVars;
1052
1053class wxSetEnvModule : public wxModule
1054{
1055public:
1056 virtual bool OnInit() { return true; }
1057 virtual void OnExit()
1058 {
1059 for ( wxEnvVars::const_iterator i = gs_envVars.begin();
1060 i != gs_envVars.end();
1061 ++i )
1062 {
1063 free(i->second);
1064 }
1065
1066 gs_envVars.clear();
1067 }
1068
1069 DECLARE_DYNAMIC_CLASS(wxSetEnvModule)
1070};
1071
1072IMPLEMENT_DYNAMIC_CLASS(wxSetEnvModule, wxModule)
1073
1074#endif // USE_PUTENV
1075
97b305b7 1076bool wxGetEnv(const wxString& var, wxString *value)
308978f6
VZ
1077{
1078 // wxGetenv is defined as getenv()
86501081 1079 char *p = wxGetenv(var);
308978f6 1080 if ( !p )
9d8aca48 1081 return false;
308978f6
VZ
1082
1083 if ( value )
1084 {
1085 *value = p;
1086 }
1087
9d8aca48 1088 return true;
308978f6
VZ
1089}
1090
90a77e64 1091static bool wxDoSetEnv(const wxString& variable, const char *value)
8fd0d89b
VZ
1092{
1093#if defined(HAVE_SETENV)
a1353ea4
VZ
1094 if ( !value )
1095 {
1096#ifdef HAVE_UNSETENV
65fd2fc2
VZ
1097 // don't test unsetenv() return value: it's void on some systems (at
1098 // least Darwin)
1099 unsetenv(variable.mb_str());
022a8d02 1100 return true;
a1353ea4
VZ
1101#else
1102 value = ""; // we can't pass NULL to setenv()
1103#endif
1104 }
1105
90a77e64 1106 return setenv(variable.mb_str(), value, 1 /* overwrite */) == 0;
8fd0d89b
VZ
1107#elif defined(HAVE_PUTENV)
1108 wxString s = variable;
1109 if ( value )
1110 s << _T('=') << value;
1111
1112 // transform to ANSI
67479dbd 1113 const wxWX2MBbuf p = s.mb_str();
8fd0d89b 1114
8fd0d89b
VZ
1115 char *buf = (char *)malloc(strlen(p) + 1);
1116 strcpy(buf, p);
1117
c0472c7c
VZ
1118 // store the string to free() it later
1119 wxEnvVars::iterator i = gs_envVars.find(variable);
1120 if ( i != gs_envVars.end() )
1121 {
1122 free(i->second);
1123 i->second = buf;
1124 }
1125 else // this variable hadn't been set before
1126 {
1127 gs_envVars[variable] = buf;
1128 }
1129
8fd0d89b
VZ
1130 return putenv(buf) == 0;
1131#else // no way to set an env var
67479dbd 1132 return false;
8fd0d89b
VZ
1133#endif
1134}
1135
90a77e64
VS
1136bool wxSetEnv(const wxString& variable, const wxString& value)
1137{
1138 return wxDoSetEnv(variable, value.mb_str());
1139}
1140
1141bool wxUnsetEnv(const wxString& variable)
1142{
1143 return wxDoSetEnv(variable, NULL);
1144}
1145
a37a5a73
VZ
1146// ----------------------------------------------------------------------------
1147// signal handling
1148// ----------------------------------------------------------------------------
1149
1150#if wxUSE_ON_FATAL_EXCEPTION
1151
1152#include <signal.h>
1153
90350682 1154extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER)
a37a5a73
VZ
1155{
1156 if ( wxTheApp )
1157 {
1158 // give the user a chance to do something special about this
1159 wxTheApp->OnFatalException();
1160 }
1161
1162 abort();
1163}
1164
1165bool wxHandleFatalExceptions(bool doit)
1166{
1167 // old sig handlers
9d8aca48 1168 static bool s_savedHandlers = false;
a37a5a73
VZ
1169 static struct sigaction s_handlerFPE,
1170 s_handlerILL,
1171 s_handlerBUS,
1172 s_handlerSEGV;
1173
9d8aca48 1174 bool ok = true;
a37a5a73
VZ
1175 if ( doit && !s_savedHandlers )
1176 {
1177 // install the signal handler
1178 struct sigaction act;
1179
1180 // some systems extend it with non std fields, so zero everything
1181 memset(&act, 0, sizeof(act));
1182
1183 act.sa_handler = wxFatalSignalHandler;
1184 sigemptyset(&act.sa_mask);
1185 act.sa_flags = 0;
1186
1187 ok &= sigaction(SIGFPE, &act, &s_handlerFPE) == 0;
1188 ok &= sigaction(SIGILL, &act, &s_handlerILL) == 0;
1189 ok &= sigaction(SIGBUS, &act, &s_handlerBUS) == 0;
1190 ok &= sigaction(SIGSEGV, &act, &s_handlerSEGV) == 0;
1191 if ( !ok )
1192 {
1193 wxLogDebug(_T("Failed to install our signal handler."));
1194 }
1195
9d8aca48 1196 s_savedHandlers = true;
a37a5a73
VZ
1197 }
1198 else if ( s_savedHandlers )
1199 {
1200 // uninstall the signal handler
1201 ok &= sigaction(SIGFPE, &s_handlerFPE, NULL) == 0;
1202 ok &= sigaction(SIGILL, &s_handlerILL, NULL) == 0;
1203 ok &= sigaction(SIGBUS, &s_handlerBUS, NULL) == 0;
1204 ok &= sigaction(SIGSEGV, &s_handlerSEGV, NULL) == 0;
1205 if ( !ok )
1206 {
1207 wxLogDebug(_T("Failed to uninstall our signal handler."));
1208 }
1209
9d8aca48 1210 s_savedHandlers = false;
a37a5a73
VZ
1211 }
1212 //else: nothing to do
1213
1214 return ok;
1215}
1216
1217#endif // wxUSE_ON_FATAL_EXCEPTION
1218
ec67cff1 1219#endif // wxUSE_BASE
e2478fde
VZ
1220
1221#if wxUSE_GUI
1222
1a6d6b10
DE
1223#if __DARWIN__
1224 #include <sys/errno.h>
1225#endif
e2478fde
VZ
1226// ----------------------------------------------------------------------------
1227// wxExecute support
1228// ----------------------------------------------------------------------------
1229
a3261ffb
DE
1230/*
1231 NOTE: If this proves not to work well for wxMac then move back to the old
1232 behavior. If, however, it proves to work just fine, nuke all of the code
1233 for the old behavior. I strongly suggest backporting this to 2.8 as well.
1234 However, beware that while you can nuke the old code here, you cannot
1235 nuke the wxAddProcessCallbackForPid from the 2.8 branch (found in
1236 utilsexc_cf since it's an exported symbol).
1237 */
1238// #define USE_OLD_DARWIN_END_PROCESS_DETECT (defined(__DARWIN__) && defined(__WXMAC__))
1239#define USE_OLD_DARWIN_END_PROCESS_DETECT 0
1a6d6b10
DE
1240
1241// wxMac/wxCocoa don't use the same process end detection mechanisms so we don't
1242// need wxExecute-related helpers for them
1243#if !USE_OLD_DARWIN_END_PROCESS_DETECT
e2478fde
VZ
1244
1245bool wxGUIAppTraits::CreateEndProcessPipe(wxExecuteData& execData)
1246{
1247 return execData.pipeEndProcDetect.Create();
1248}
1249
1250bool wxGUIAppTraits::IsWriteFDOfEndProcessPipe(wxExecuteData& execData, int fd)
1251{
46446cc2 1252 return fd == (execData.pipeEndProcDetect)[wxPipe::Write];
e2478fde
VZ
1253}
1254
1255void wxGUIAppTraits::DetachWriteFDOfEndProcessPipe(wxExecuteData& execData)
1256{
1257 execData.pipeEndProcDetect.Detach(wxPipe::Write);
1258 execData.pipeEndProcDetect.Close();
1259}
1260
1261#else // !Darwin
1262
1263bool wxGUIAppTraits::CreateEndProcessPipe(wxExecuteData& WXUNUSED(execData))
1264{
1265 return true;
1266}
1267
1268bool
1269wxGUIAppTraits::IsWriteFDOfEndProcessPipe(wxExecuteData& WXUNUSED(execData),
1270 int WXUNUSED(fd))
1271{
1272 return false;
1273}
1274
1275void
1276wxGUIAppTraits::DetachWriteFDOfEndProcessPipe(wxExecuteData& WXUNUSED(execData))
1277{
1278 // nothing to do here, we don't use the pipe
1279}
1280
1281#endif // !Darwin/Darwin
1282
1283int wxGUIAppTraits::WaitForChild(wxExecuteData& execData)
1284{
1285 wxEndProcessData *endProcData = new wxEndProcessData;
1286
f38f6899
VZ
1287 const int flags = execData.flags;
1288
e2478fde
VZ
1289 // wxAddProcessCallback is now (with DARWIN) allowed to call the
1290 // callback function directly if the process terminates before
1291 // the callback can be added to the run loop. Set up the endProcData.
f38f6899 1292 if ( flags & wxEXEC_SYNC )
e2478fde
VZ
1293 {
1294 // we may have process for capturing the program output, but it's
1295 // not used in wxEndProcessData in the case of sync execution
1296 endProcData->process = NULL;
1297
1298 // sync execution: indicate it by negating the pid
1299 endProcData->pid = -execData.pid;
1300 }
1301 else
1302 {
1303 // async execution, nothing special to do -- caller will be
1304 // notified about the process termination if process != NULL, endProcData
1305 // will be deleted in GTK_EndProcessDetector
1306 endProcData->process = execData.process;
1307 endProcData->pid = execData.pid;
1308 }
1309
1310
bc855d09
VZ
1311 if ( !(flags & wxEXEC_NOEVENTS) )
1312 {
1a6d6b10 1313#if USE_OLD_DARWIN_END_PROCESS_DETECT
bc855d09 1314 endProcData->tag = wxAddProcessCallbackForPid(endProcData, execData.pid);
e2478fde 1315#else
bc855d09
VZ
1316 endProcData->tag = wxAddProcessCallback
1317 (
1318 endProcData,
1319 execData.pipeEndProcDetect.Detach(wxPipe::Read)
1320 );
e2478fde 1321
bc855d09 1322 execData.pipeEndProcDetect.Close();
1a6d6b10 1323#endif // USE_OLD_DARWIN_END_PROCESS_DETECT
bc855d09 1324 }
e2478fde 1325
f38f6899 1326 if ( flags & wxEXEC_SYNC )
e2478fde
VZ
1327 {
1328 wxBusyCursor bc;
bc855d09
VZ
1329 int exitcode = 0;
1330
1331 wxWindowDisabler *wd = flags & (wxEXEC_NODISABLE | wxEXEC_NOEVENTS)
1332 ? NULL
1333 : new wxWindowDisabler;
e2478fde 1334
bc855d09 1335 if ( flags & wxEXEC_NOEVENTS )
e2478fde 1336 {
bc855d09
VZ
1337 // just block waiting for the child to exit
1338 int status = 0;
05df0f1b 1339
bc855d09 1340 int result = waitpid(execData.pid, &status, 0);
1a6d6b10
DE
1341#ifdef __DARWIN__
1342 /* DE: waitpid manpage states that waitpid can fail with EINTR
1343 if the call is interrupted by a caught signal. I suppose
1344 that means that this ought to be a while loop.
1345
1346 The odd thing is that it seems to fail EVERY time. It fails
1347 with a quickly exiting process (e.g. echo), and fails with a
1348 slowly exiting process (e.g. sleep 2) but clearly after
1349 having waited for the child to exit. Maybe it's a bug in
1350 my particular version.
1351
1352 It works, however, from the CFSocket callback without this
1353 trick but in that case it's used only after CFSocket calls
1354 the callback and with the WNOHANG flag which would seem to
1355 preclude it from being interrupted or at least make it much
1356 less likely since it would not then be waiting.
1357
1358 If Darwin's man page is to be believed then this is definitely
1359 necessary. It's just weird that I've never seen it before
1360 and apparently no one else has either or you'd think they'd
1361 have reported it by now. Perhaps blocking the GUI while
1362 waiting for a child process to exit is simply not that common.
1363 */
1364 if(result == -1 && errno == EINTR)
1365 {
1366 result = waitpid(execData.pid, &status, 0);
1367 }
1368
1369#endif
bc855d09
VZ
1370
1371 if ( result == -1 )
05df0f1b 1372 {
bc855d09
VZ
1373 wxLogLastError(_T("waitpid"));
1374 exitcode = -1;
05df0f1b 1375 }
bc855d09 1376 else
05df0f1b 1377 {
bc855d09
VZ
1378 wxASSERT_MSG( result == execData.pid,
1379 _T("unexpected waitpid() return value") );
1380
1381 if ( WIFEXITED(status) )
1382 {
1383 exitcode = WEXITSTATUS(status);
1384 }
1385 else // abnormal termination?
1386 {
1387 wxASSERT_MSG( WIFSIGNALED(status),
1388 _T("unexpected child wait status") );
1389 exitcode = -1;
1390 }
05df0f1b 1391 }
bc855d09
VZ
1392 }
1393 else // !wxEXEC_NOEVENTS
1394 {
1395 // endProcData->pid will be set to 0 from GTK_EndProcessDetector when the
1396 // process terminates
1397 while ( endProcData->pid != 0 )
1398 {
1399 bool idle = true;
1400
1401#if HAS_PIPE_INPUT_STREAM
1402 if ( execData.bufOut )
1403 {
1404 execData.bufOut->Update();
1405 idle = false;
1406 }
1407
1408 if ( execData.bufErr )
1409 {
1410 execData.bufErr->Update();
1411 idle = false;
1412 }
1f3b2af0 1413#endif // HAS_PIPE_INPUT_STREAM
e2478fde 1414
bc855d09
VZ
1415 // don't consume 100% of the CPU while we're sitting in this
1416 // loop
1417 if ( idle )
1418 wxMilliSleep(1);
05df0f1b 1419
bc855d09
VZ
1420 // give GTK+ a chance to call GTK_EndProcessDetector here and
1421 // also repaint the GUI
1422 wxYield();
1423 }
e2478fde 1424
bc855d09
VZ
1425 exitcode = endProcData->exitcode;
1426 }
e2478fde 1427
f38f6899 1428 delete wd;
e2478fde
VZ
1429 delete endProcData;
1430
1431 return exitcode;
1432 }
1433 else // async execution
1434 {
1435 return execData.pid;
1436 }
1437}
1438
2dbc444a
RD
1439#endif // wxUSE_GUI
1440#if wxUSE_BASE
1441
e2478fde
VZ
1442void wxHandleProcessTermination(wxEndProcessData *proc_data)
1443{
1444 // notify user about termination if required
1445 if ( proc_data->process )
1446 {
1447 proc_data->process->OnTerminate(proc_data->pid, proc_data->exitcode);
1448 }
1449
1450 // clean up
1451 if ( proc_data->pid > 0 )
1452 {
1453 delete proc_data;
1454 }
1455 else
1456 {
1457 // let wxExecute() know that the process has terminated
1458 proc_data->pid = 0;
1459 }
1460}
1461
2dbc444a 1462#endif // wxUSE_BASE