]> git.saurik.com Git - wxWidgets.git/blame - src/unix/utilsunx.cpp
added wxApp::Yield()
[wxWidgets.git] / src / unix / utilsunx.cpp
CommitLineData
518b5d2f
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: utilsunx.cpp
3// Purpose: generic Unix implementation of many wx functions
4// Author: Vadim Zeitlin
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// ============================================================================
11// declarations
12// ============================================================================
13
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
18#include "wx/defs.h"
19#include "wx/string.h"
20
21#include "wx/intl.h"
22#include "wx/log.h"
a37a5a73 23#include "wx/app.h"
518b5d2f
VZ
24
25#include "wx/utils.h"
26#include "wx/process.h"
bdc72a22 27#include "wx/thread.h"
518b5d2f 28
8b33ae2d
GL
29#include "wx/stream.h"
30
eadd7bd2 31#ifdef HAVE_STATFS
8f17876f 32# ifdef __BSD__
8c03f242
GD
33# include <sys/param.h>
34# include <sys/mount.h>
35# else
36# include <sys/vfs.h>
37# endif
eadd7bd2
VZ
38#endif // HAVE_STATFS
39
6dc6fda6
VZ
40#if wxUSE_GUI
41 #include "wx/unix/execute.h"
42#endif
518b5d2f 43
f6bcfd97
BP
44// SGI signal.h defines signal handler arguments differently depending on
45// whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it
46#if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS)
47 #define _LANGUAGE_C_PLUS_PLUS 1
48#endif // SGI hack
49
518b5d2f
VZ
50#include <stdarg.h>
51#include <dirent.h>
52#include <string.h>
53#include <sys/stat.h>
54#include <sys/types.h>
55#include <unistd.h>
56#include <sys/wait.h>
57#include <pwd.h>
58#include <errno.h>
59#include <netdb.h>
60#include <signal.h>
61#include <fcntl.h> // for O_WRONLY and friends
62#include <time.h> // nanosleep() and/or usleep()
fad866f4 63#include <ctype.h> // isspace()
b12915c1 64#include <sys/time.h> // needed for FD_SETSIZE
7bcb11d3 65
0fcdf6dc 66#ifdef HAVE_UNAME
518b5d2f
VZ
67 #include <sys/utsname.h> // for uname()
68#endif // HAVE_UNAME
69
70// ----------------------------------------------------------------------------
71// conditional compilation
72// ----------------------------------------------------------------------------
73
74// many versions of Unices have this function, but it is not defined in system
75// headers - please add your system here if it is the case for your OS.
76// SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
1363811b
VZ
77#if !defined(HAVE_USLEEP) && \
78 (defined(__SUN__) && !defined(__SunOs_5_6) && \
518b5d2f 79 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
fd9811b1 80 defined(__osf__) || defined(__EMX__)
518b5d2f
VZ
81 extern "C"
82 {
1363811b
VZ
83 #ifdef __SUN__
84 int usleep(unsigned int usec);
85 #else // !Sun
bdc72a22
VZ
86 #ifdef __EMX__
87 /* I copied this from the XFree86 diffs. AV. */
88 #define INCL_DOSPROCESS
89 #include <os2.h>
90 inline void usleep(unsigned long delay)
91 {
92 DosSleep(delay ? (delay/1000l) : 1l);
93 }
94 #else // !Sun && !EMX
95 void usleep(unsigned long usec);
96 #endif
e6daf794 97 #endif // Sun/EMX/Something else
518b5d2f 98 };
bdc72a22
VZ
99
100 #define HAVE_USLEEP 1
518b5d2f
VZ
101#endif // Unices without usleep()
102
518b5d2f
VZ
103// ============================================================================
104// implementation
105// ============================================================================
106
107// ----------------------------------------------------------------------------
108// sleeping
109// ----------------------------------------------------------------------------
110
111void wxSleep(int nSecs)
112{
113 sleep(nSecs);
114}
115
116void wxUsleep(unsigned long milliseconds)
117{
b12915c1 118#if defined(HAVE_NANOSLEEP)
518b5d2f 119 timespec tmReq;
13111b2a 120 tmReq.tv_sec = (time_t)(milliseconds / 1000);
518b5d2f
VZ
121 tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
122
123 // we're not interested in remaining time nor in return value
124 (void)nanosleep(&tmReq, (timespec *)NULL);
b12915c1 125#elif defined(HAVE_USLEEP)
518b5d2f
VZ
126 // uncomment this if you feel brave or if you are sure that your version
127 // of Solaris has a safe usleep() function but please notice that usleep()
128 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
129 // documented as MT-Safe
ea18eed9 130 #if defined(__SUN__) && wxUSE_THREADS
518b5d2f
VZ
131 #error "usleep() cannot be used in MT programs under Solaris."
132 #endif // Sun
133
134 usleep(milliseconds * 1000); // usleep(3) wants microseconds
b12915c1
VZ
135#elif defined(HAVE_SLEEP)
136 // under BeOS sleep() takes seconds (what about other platforms, if any?)
137 sleep(milliseconds * 1000);
518b5d2f
VZ
138#else // !sleep function
139 #error "usleep() or nanosleep() function required for wxUsleep"
140#endif // sleep function
141}
142
143// ----------------------------------------------------------------------------
144// process management
145// ----------------------------------------------------------------------------
146
50567b69 147int wxKill(long pid, wxSignal sig, wxKillError *rc)
518b5d2f 148{
50567b69
VZ
149 int err = kill((pid_t)pid, (int)sig);
150 if ( rc )
151 {
152 switch ( err )
153 {
154 case 0:
155 *rc = wxKILL_OK;
156 break;
157
158 case EINVAL:
159 *rc = wxKILL_BAD_SIGNAL;
160 break;
161
162 case EPERM:
163 *rc = wxKILL_ACCESS_DENIED;
164 break;
165
166 case ESRCH:
167 *rc = wxKILL_NO_PROCESS;
168 break;
169
170 default:
171 // this goes against Unix98 docs so log it
172 wxLogDebug(_T("unexpected kill(2) return value %d"), err);
173
174 // something else...
175 *rc = wxKILL_ERROR;
176 }
177 }
178
179 return err;
518b5d2f
VZ
180}
181
fad866f4
KB
182#define WXEXECUTE_NARGS 127
183
518b5d2f
VZ
184long wxExecute( const wxString& command, bool sync, wxProcess *process )
185{
223d09f6 186 wxCHECK_MSG( !command.IsEmpty(), 0, wxT("can't exec empty command") );
518b5d2f
VZ
187
188 int argc = 0;
05079acc 189 wxChar *argv[WXEXECUTE_NARGS];
fad866f4 190 wxString argument;
05079acc 191 const wxChar *cptr = command.c_str();
223d09f6 192 wxChar quotechar = wxT('\0'); // is arg quoted?
fad866f4 193 bool escaped = FALSE;
518b5d2f 194
0ed9a934 195 // split the command line in arguments
fad866f4
KB
196 do
197 {
223d09f6
KB
198 argument=wxT("");
199 quotechar = wxT('\0');
0ed9a934 200
fad866f4 201 // eat leading whitespace:
05079acc 202 while ( wxIsspace(*cptr) )
fad866f4 203 cptr++;
0ed9a934 204
223d09f6 205 if ( *cptr == wxT('\'') || *cptr == wxT('"') )
fad866f4 206 quotechar = *cptr++;
0ed9a934 207
fad866f4
KB
208 do
209 {
223d09f6 210 if ( *cptr == wxT('\\') && ! escaped )
fad866f4
KB
211 {
212 escaped = TRUE;
213 cptr++;
214 continue;
215 }
0ed9a934 216
fad866f4 217 // all other characters:
0ed9a934 218 argument += *cptr++;
fad866f4 219 escaped = FALSE;
0ed9a934
VZ
220
221 // have we reached the end of the argument?
222 if ( (*cptr == quotechar && ! escaped)
223d09f6
KB
223 || (quotechar == wxT('\0') && wxIsspace(*cptr))
224 || *cptr == wxT('\0') )
fad866f4 225 {
0ed9a934 226 wxASSERT_MSG( argc < WXEXECUTE_NARGS,
223d09f6 227 wxT("too many arguments in wxExecute") );
0ed9a934 228
05079acc
OK
229 argv[argc] = new wxChar[argument.length() + 1];
230 wxStrcpy(argv[argc], argument.c_str());
fad866f4 231 argc++;
0ed9a934 232
fad866f4 233 // if not at end of buffer, swallow last character:
0ed9a934
VZ
234 if(*cptr)
235 cptr++;
236
fad866f4
KB
237 break; // done with this one, start over
238 }
0ed9a934
VZ
239 } while(*cptr);
240 } while(*cptr);
fad866f4 241 argv[argc] = NULL;
0ed9a934
VZ
242
243 // do execute the command
518b5d2f
VZ
244 long lRc = wxExecute(argv, sync, process);
245
0ed9a934 246 // clean up
fad866f4 247 argc = 0;
0ed9a934 248 while( argv[argc] )
fad866f4 249 delete [] argv[argc++];
518b5d2f
VZ
250
251 return lRc;
252}
253
2c8e4738
VZ
254// ----------------------------------------------------------------------------
255// wxShell
256// ----------------------------------------------------------------------------
257
258static wxString wxMakeShellCommand(const wxString& command)
518b5d2f
VZ
259{
260 wxString cmd;
cd6ce4a9 261 if ( !command )
2c8e4738
VZ
262 {
263 // just an interactive shell
cd6ce4a9 264 cmd = _T("xterm");
2c8e4738 265 }
518b5d2f 266 else
2c8e4738
VZ
267 {
268 // execute command in a shell
269 cmd << _T("/bin/sh -c '") << command << _T('\'');
270 }
271
272 return cmd;
273}
274
275bool wxShell(const wxString& command)
276{
277 return wxExecute(wxMakeShellCommand(command), TRUE /* sync */) == 0;
278}
279
280bool wxShell(const wxString& command, wxArrayString& output)
281{
282 wxCHECK_MSG( !!command, FALSE, _T("can't exec shell non interactively") );
518b5d2f 283
2c8e4738 284 return wxExecute(wxMakeShellCommand(command), output);
518b5d2f
VZ
285}
286
6dc6fda6
VZ
287#if wxUSE_GUI
288
518b5d2f
VZ
289void wxHandleProcessTermination(wxEndProcessData *proc_data)
290{
018e2f13
VZ
291 // notify user about termination if required
292 if ( proc_data->process )
c556f198 293 {
447f908a 294 proc_data->process->OnTerminate(proc_data->pid, proc_data->exitcode);
c556f198 295 }
447f908a 296
018e2f13
VZ
297 // clean up
298 if ( proc_data->pid > 0 )
c556f198 299 {
018e2f13 300 delete proc_data;
0ed9a934 301 }
018e2f13 302 else
0ed9a934 303 {
447f908a 304 // let wxExecute() know that the process has terminated
018e2f13 305 proc_data->pid = 0;
518b5d2f
VZ
306 }
307}
308
6dc6fda6
VZ
309#endif // wxUSE_GUI
310
cd6ce4a9
VZ
311// ----------------------------------------------------------------------------
312// wxStream classes to support IO redirection in wxExecute
313// ----------------------------------------------------------------------------
6dc6fda6 314
1e6feb95
VZ
315#if wxUSE_STREAMS
316
cd6ce4a9
VZ
317class wxProcessFileInputStream : public wxInputStream
318{
319public:
320 wxProcessFileInputStream(int fd) { m_fd = fd; }
321 ~wxProcessFileInputStream() { close(m_fd); }
8b33ae2d 322
cd6ce4a9 323 virtual bool Eof() const;
8b33ae2d 324
cd6ce4a9 325protected:
8b33ae2d
GL
326 size_t OnSysRead(void *buffer, size_t bufsize);
327
cd6ce4a9 328protected:
8b33ae2d
GL
329 int m_fd;
330};
331
cd6ce4a9
VZ
332class wxProcessFileOutputStream : public wxOutputStream
333{
334public:
335 wxProcessFileOutputStream(int fd) { m_fd = fd; }
336 ~wxProcessFileOutputStream() { close(m_fd); }
8b33ae2d 337
cd6ce4a9 338protected:
8b33ae2d
GL
339 size_t OnSysWrite(const void *buffer, size_t bufsize);
340
cd6ce4a9 341protected:
8b33ae2d
GL
342 int m_fd;
343};
344
cd6ce4a9 345bool wxProcessFileInputStream::Eof() const
8b33ae2d 346{
cd6ce4a9
VZ
347 if ( m_lasterror == wxSTREAM_EOF )
348 return TRUE;
349
350 // check if there is any input available
351 struct timeval tv;
352 tv.tv_sec = 0;
353 tv.tv_usec = 0;
354
355 fd_set readfds;
356 FD_ZERO(&readfds);
357 FD_SET(m_fd, &readfds);
358 switch ( select(m_fd + 1, &readfds, NULL, NULL, &tv) )
359 {
360 case -1:
361 wxLogSysError(_("Impossible to get child process input"));
362 // fall through
8b33ae2d 363
cd6ce4a9
VZ
364 case 0:
365 return TRUE;
8b33ae2d 366
cd6ce4a9
VZ
367 default:
368 wxFAIL_MSG(_T("unexpected select() return value"));
369 // still fall through
370
371 case 1:
372 // input available: check if there is any
373 return wxInputStream::Eof();
8b33ae2d 374 }
8b33ae2d
GL
375}
376
cd6ce4a9 377size_t wxProcessFileInputStream::OnSysRead(void *buffer, size_t bufsize)
8b33ae2d 378{
cd6ce4a9
VZ
379 int ret = read(m_fd, buffer, bufsize);
380 if ( ret == 0 )
381 {
382 m_lasterror = wxSTREAM_EOF;
383 }
384 else if ( ret == -1 )
385 {
386 m_lasterror = wxSTREAM_READ_ERROR;
387 ret = 0;
388 }
389 else
390 {
391 m_lasterror = wxSTREAM_NOERROR;
392 }
8b33ae2d 393
cd6ce4a9 394 return ret;
8b33ae2d
GL
395}
396
397size_t wxProcessFileOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
398{
cd6ce4a9
VZ
399 int ret = write(m_fd, buffer, bufsize);
400 if ( ret == -1 )
401 {
402 m_lasterror = wxSTREAM_WRITE_ERROR;
403 ret = 0;
8b33ae2d 404 }
cd6ce4a9
VZ
405 else
406 {
407 m_lasterror = wxSTREAM_NOERROR;
408 }
409
8b33ae2d
GL
410 return ret;
411}
412
0e300ddd
VZ
413// ----------------------------------------------------------------------------
414// wxStreamTempBuffer
415// ----------------------------------------------------------------------------
416
417/*
418 Extract of a mail to wx-users to give the context of the problem we are
419 trying to solve here:
420
421 MC> If I run the command:
422 MC> find . -name "*.h" -exec grep linux {} \;
423 MC> in the exec sample synchronously from the 'Capture command output'
424 MC> menu, wxExecute never returns. I have to xkill it. Has anyone
425 MC> else encountered this?
426
427 Yes, I can reproduce it too.
428
429 I even think I understand why it happens: before launching the external
430 command we set up a pipe with a valid file descriptor on the reading side
431 when the output is redirected. So the subprocess happily writes to it ...
432 until the pipe buffer (which is usually quite big on Unix, I think the
433 default is 4Mb) is full. Then the writing process stops and waits until we
434 read some data from the pipe to be able to continue writing to it but we
435 never do it because we wait until it terminates to start reading and so we
436 have a classical deadlock.
437
438 Here is the fix: we now read the output as soon as it appears into a temp
439 buffer (wxStreamTempBuffer object) and later just stuff it back into the
440 stream when the process terminates. See supporting code in wxExecute()
441 itself as well.
442*/
443
444class wxStreamTempBuffer
445{
446public:
447 wxStreamTempBuffer();
448
449 // call to associate a stream with this buffer, otherwise nothing happens
450 // at all
451 void Init(wxInputStream *stream);
452
453 // check for input on our stream and cache it in our buffer if any
454 void Update();
455
456 ~wxStreamTempBuffer();
457
458private:
459 // the stream we're buffering, if NULL we don't do anything at all
460 wxInputStream *m_stream;
461
462 // the buffer of size m_size (NULL if m_size == 0)
463 void *m_buffer;
464
465 // the size of the buffer
466 size_t m_size;
467};
468
469wxStreamTempBuffer::wxStreamTempBuffer()
470{
471 m_stream = NULL;
472 m_buffer = NULL;
473 m_size = 0;
474}
475
476void wxStreamTempBuffer::Init(wxInputStream *stream)
477{
478 m_stream = stream;
479}
480
481void wxStreamTempBuffer::Update()
482{
483 if ( m_stream && !m_stream->Eof() )
484 {
485 // realloc in blocks of 1Kb - surely not the best strategy but which
486 // one is?
487 static const size_t incSize = 1024;
488
489 void *buf = realloc(m_buffer, m_size + incSize);
490 if ( !buf )
491 {
492 // don't read any more, we don't have enough memory to do it
493 m_stream = NULL;
494 }
495 else // got memory for the buffer
496 {
497 m_buffer = buf;
498 m_stream->Read((char *)m_buffer + m_size, incSize);
499 m_size += incSize;
500 }
501 }
502}
503
504wxStreamTempBuffer::~wxStreamTempBuffer()
505{
506 if ( m_buffer )
507 {
508 m_stream->Ungetch(m_buffer, m_size);
509 free(m_buffer);
510 }
511}
512
1e6feb95
VZ
513#endif // wxUSE_STREAMS
514
6dc6fda6
VZ
515long wxExecute(wxChar **argv,
516 bool sync,
cd6ce4a9 517 wxProcess *process)
518b5d2f 518{
f6bcfd97 519 // for the sync execution, we return -1 to indicate failure, but for async
accb3257
VZ
520 // case we return 0 which is never a valid PID
521 //
522 // we define this as a macro, not a variable, to avoid compiler warnings
523 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
524 #define ERROR_RETURN_CODE ((sync) ? -1 : 0)
f6bcfd97 525
accb3257 526 wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") );
518b5d2f 527
05079acc
OK
528#if wxUSE_UNICODE
529 int mb_argc = 0;
530 char *mb_argv[WXEXECUTE_NARGS];
531
e90c1d2a
VZ
532 while (argv[mb_argc])
533 {
cd6ce4a9
VZ
534 wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
535 mb_argv[mb_argc] = strdup(mb_arg);
536 mb_argc++;
05079acc
OK
537 }
538 mb_argv[mb_argc] = (char *) NULL;
e90c1d2a
VZ
539
540 // this macro will free memory we used above
541 #define ARGS_CLEANUP \
345b0247 542 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
e90c1d2a
VZ
543 free(mb_argv[mb_argc])
544#else // ANSI
545 // no need for cleanup
546 #define ARGS_CLEANUP
547
05079acc 548 wxChar **mb_argv = argv;
e90c1d2a 549#endif // Unicode/ANSI
518b5d2f 550
e90c1d2a 551#if wxUSE_GUI
518b5d2f 552 // create pipes
e90c1d2a 553 int end_proc_detect[2];
cd6ce4a9 554 if ( pipe(end_proc_detect) == -1 )
518b5d2f
VZ
555 {
556 wxLogSysError( _("Pipe creation failed") );
cd6ce4a9 557 wxLogError( _("Failed to execute '%s'\n"), *argv );
e90c1d2a
VZ
558
559 ARGS_CLEANUP;
560
accb3257 561 return ERROR_RETURN_CODE;
518b5d2f 562 }
e90c1d2a 563#endif // wxUSE_GUI
518b5d2f 564
f6bcfd97
BP
565 // pipes for inter process communication
566 int pipeIn[2], // stdin
567 pipeOut[2], // stdout
568 pipeErr[2]; // stderr
569
cd6ce4a9 570 pipeIn[0] = pipeIn[1] =
f6bcfd97
BP
571 pipeOut[0] = pipeOut[1] =
572 pipeErr[0] = pipeErr[1] = -1;
cd6ce4a9
VZ
573
574 if ( process && process->IsRedirected() )
8b33ae2d 575 {
f6bcfd97 576 if ( pipe(pipeIn) == -1 || pipe(pipeOut) == -1 || pipe(pipeErr) == -1 )
8b33ae2d 577 {
cd6ce4a9
VZ
578#if wxUSE_GUI
579 // free previously allocated resources
8b33ae2d
GL
580 close(end_proc_detect[0]);
581 close(end_proc_detect[1]);
cd6ce4a9
VZ
582#endif // wxUSE_GUI
583
584 wxLogSysError( _("Pipe creation failed") );
585 wxLogError( _("Failed to execute '%s'\n"), *argv );
8b33ae2d
GL
586
587 ARGS_CLEANUP;
588
accb3257 589 return ERROR_RETURN_CODE;
8b33ae2d
GL
590 }
591 }
8b33ae2d 592
518b5d2f 593 // fork the process
0fcdf6dc 594#ifdef HAVE_VFORK
518b5d2f
VZ
595 pid_t pid = vfork();
596#else
597 pid_t pid = fork();
598#endif
cd6ce4a9
VZ
599
600 if ( pid == -1 ) // error?
518b5d2f 601 {
8b33ae2d
GL
602#if wxUSE_GUI
603 close(end_proc_detect[0]);
604 close(end_proc_detect[1]);
cd6ce4a9
VZ
605 close(pipeIn[0]);
606 close(pipeIn[1]);
607 close(pipeOut[0]);
608 close(pipeOut[1]);
f6bcfd97
BP
609 close(pipeErr[0]);
610 close(pipeErr[1]);
cd6ce4a9
VZ
611#endif // wxUSE_GUI
612
518b5d2f 613 wxLogSysError( _("Fork failed") );
e90c1d2a
VZ
614
615 ARGS_CLEANUP;
616
accb3257 617 return ERROR_RETURN_CODE;
518b5d2f 618 }
cd6ce4a9 619 else if ( pid == 0 ) // we're in child
518b5d2f 620 {
e90c1d2a 621#if wxUSE_GUI
518b5d2f 622 close(end_proc_detect[0]); // close reading side
e90c1d2a 623#endif // wxUSE_GUI
518b5d2f 624
cd6ce4a9 625 // These lines close the open file descriptors to to avoid any
518b5d2f 626 // input/output which might block the process or irritate the user. If
cd6ce4a9
VZ
627 // one wants proper IO for the subprocess, the right thing to do is to
628 // start an xterm executing it.
629 if ( !sync )
518b5d2f 630 {
518b5d2f
VZ
631 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
632 {
f6bcfd97 633 if ( fd == pipeIn[0] || fd == pipeOut[1] || fd == pipeErr[1]
e90c1d2a 634#if wxUSE_GUI
cd6ce4a9 635 || fd == end_proc_detect[1]
e90c1d2a 636#endif // wxUSE_GUI
cd6ce4a9
VZ
637 )
638 {
639 // don't close this one, we still need it
640 continue;
641 }
e90c1d2a 642
cd6ce4a9 643 // leave stderr opened too, it won't do any hurm
e90c1d2a 644 if ( fd != STDERR_FILENO )
518b5d2f
VZ
645 close(fd);
646 }
647 }
648
f6bcfd97 649 // redirect stdio, stdout and stderr
cd6ce4a9
VZ
650 if ( pipeIn[0] != -1 )
651 {
652 if ( dup2(pipeIn[0], STDIN_FILENO) == -1 ||
f6bcfd97
BP
653 dup2(pipeOut[1], STDOUT_FILENO) == -1 ||
654 dup2(pipeErr[1], STDERR_FILENO) == -1 )
cd6ce4a9 655 {
f6bcfd97 656 wxLogSysError(_("Failed to redirect child process input/output"));
cd6ce4a9 657 }
518b5d2f 658
cd6ce4a9
VZ
659 close(pipeIn[0]);
660 close(pipeOut[1]);
f6bcfd97 661 close(pipeErr[1]);
cd6ce4a9 662 }
518b5d2f 663
05079acc 664 execvp (*mb_argv, mb_argv);
518b5d2f
VZ
665
666 // there is no return after successful exec()
518b5d2f 667 _exit(-1);
1d8dd65e
VZ
668
669 // some compilers complain about missing return - of course, they
670 // should know that exit() doesn't return but what else can we do if
671 // they don't?
672#if defined(__VMS) || defined(__INTEL_COMPILER)
673 return 0;
674#endif
518b5d2f 675 }
cd6ce4a9 676 else // we're in parent
518b5d2f 677 {
cd6ce4a9
VZ
678 ARGS_CLEANUP;
679
680 // pipe initialization: construction of the wxStreams
0e300ddd
VZ
681#if wxUSE_STREAMS
682 wxStreamTempBuffer bufIn, bufErr;
683#endif // wxUSE_STREAMS
684
cd6ce4a9
VZ
685 if ( process && process->IsRedirected() )
686 {
1e6feb95 687#if wxUSE_STREAMS
0e300ddd 688 // in/out for subprocess correspond to our out/in
cd6ce4a9
VZ
689 wxOutputStream *outStream = new wxProcessFileOutputStream(pipeIn[1]);
690 wxInputStream *inStream = new wxProcessFileInputStream(pipeOut[0]);
f6bcfd97
BP
691 wxInputStream *errStream = new wxProcessFileInputStream(pipeErr[0]);
692
1e6feb95 693 process->SetPipeStreams(inStream, outStream, errStream);
0e300ddd
VZ
694
695 bufIn.Init(inStream);
696 bufErr.Init(inStream);
1e6feb95
VZ
697#endif // wxUSE_STREAMS
698
cd6ce4a9
VZ
699 close(pipeIn[0]); // close reading side
700 close(pipeOut[1]); // close writing side
f6bcfd97 701 close(pipeErr[1]); // close writing side
cd6ce4a9
VZ
702 }
703
fac3b423 704#if wxUSE_GUI && !defined(__WXMICROWIN__)
518b5d2f 705 wxEndProcessData *data = new wxEndProcessData;
ab857a4e 706
518b5d2f
VZ
707 if ( sync )
708 {
cd6ce4a9
VZ
709 // we may have process for capturing the program output, but it's
710 // not used in wxEndProcessData in the case of sync execution
518b5d2f
VZ
711 data->process = NULL;
712
713 // sync execution: indicate it by negating the pid
cd6ce4a9
VZ
714 data->pid = -pid;
715 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
716
ab857a4e 717 close(end_proc_detect[1]); // close writing side
518b5d2f 718
cd6ce4a9
VZ
719 wxBusyCursor bc;
720 wxWindowDisabler wd;
721
0e300ddd
VZ
722 // data->pid will be set to 0 from GTK_EndProcessDetector when the
723 // process terminates
724 while ( data->pid != 0 )
725 {
726#if wxUSE_STREAMS
727 bufIn.Update();
728 bufErr.Update();
729#endif // wxUSE_STREAMS
730
731 // give GTK+ a chance to call GTK_EndProcessDetector here and
732 // also repaint the GUI
518b5d2f 733 wxYield();
0e300ddd 734 }
518b5d2f
VZ
735
736 int exitcode = data->exitcode;
737
738 delete data;
739
740 return exitcode;
741 }
cd6ce4a9 742 else // async execution
518b5d2f
VZ
743 {
744 // async execution, nothing special to do - caller will be
ab857a4e 745 // notified about the process termination if process != NULL, data
518b5d2f 746 // will be deleted in GTK_EndProcessDetector
8b33ae2d
GL
747 data->process = process;
748 data->pid = pid;
749 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
cd6ce4a9 750
ab857a4e 751 close(end_proc_detect[1]); // close writing side
518b5d2f
VZ
752
753 return pid;
754 }
e90c1d2a 755#else // !wxUSE_GUI
223d09f6 756 wxASSERT_MSG( sync, wxT("async execution not supported yet") );
e90c1d2a
VZ
757
758 int exitcode = 0;
759 if ( waitpid(pid, &exitcode, 0) == -1 || !WIFEXITED(exitcode) )
760 {
761 wxLogSysError(_("Waiting for subprocess termination failed"));
762 }
763
764 return exitcode;
765#endif // wxUSE_GUI
518b5d2f
VZ
766 }
767}
768
accb3257 769#undef ERROR_RETURN_CODE
f6bcfd97
BP
770#undef ARGS_CLEANUP
771
518b5d2f
VZ
772// ----------------------------------------------------------------------------
773// file and directory functions
774// ----------------------------------------------------------------------------
775
05079acc 776const wxChar* wxGetHomeDir( wxString *home )
518b5d2f
VZ
777{
778 *home = wxGetUserHome( wxString() );
181cbcf4 779 wxString tmp;
518b5d2f 780 if ( home->IsEmpty() )
223d09f6 781 *home = wxT("/");
181cbcf4
JJ
782#ifdef __VMS
783 tmp = *home;
784 if ( tmp.Last() != wxT(']'))
785 if ( tmp.Last() != wxT('/')) *home << wxT('/');
786#endif
518b5d2f
VZ
787 return home->c_str();
788}
789
05079acc
OK
790#if wxUSE_UNICODE
791const wxMB2WXbuf wxGetUserHome( const wxString &user )
e90c1d2a 792#else // just for binary compatibility -- there is no 'const' here
518b5d2f 793char *wxGetUserHome( const wxString &user )
05079acc 794#endif
518b5d2f
VZ
795{
796 struct passwd *who = (struct passwd *) NULL;
797
0fb67cd1 798 if ( !user )
518b5d2f 799 {
e90c1d2a 800 wxChar *ptr;
518b5d2f 801
223d09f6 802 if ((ptr = wxGetenv(wxT("HOME"))) != NULL)
518b5d2f
VZ
803 {
804 return ptr;
805 }
223d09f6 806 if ((ptr = wxGetenv(wxT("USER"))) != NULL || (ptr = wxGetenv(wxT("LOGNAME"))) != NULL)
518b5d2f 807 {
e90c1d2a 808 who = getpwnam(wxConvertWX2MB(ptr));
518b5d2f
VZ
809 }
810
811 // We now make sure the the user exists!
812 if (who == NULL)
813 {
814 who = getpwuid(getuid());
815 }
816 }
817 else
818 {
05079acc 819 who = getpwnam (user.mb_str());
518b5d2f
VZ
820 }
821
af111fc3 822 return wxConvertMB2WX(who ? who->pw_dir : 0);
518b5d2f
VZ
823}
824
825// ----------------------------------------------------------------------------
0fb67cd1 826// network and user id routines
518b5d2f
VZ
827// ----------------------------------------------------------------------------
828
0fb67cd1
VZ
829// retrieve either the hostname or FQDN depending on platform (caller must
830// check whether it's one or the other, this is why this function is for
831// private use only)
05079acc 832static bool wxGetHostNameInternal(wxChar *buf, int sz)
518b5d2f 833{
223d09f6 834 wxCHECK_MSG( buf, FALSE, wxT("NULL pointer in wxGetHostNameInternal") );
518b5d2f 835
223d09f6 836 *buf = wxT('\0');
518b5d2f
VZ
837
838 // we're using uname() which is POSIX instead of less standard sysinfo()
839#if defined(HAVE_UNAME)
cc743a6f 840 struct utsname uts;
518b5d2f
VZ
841 bool ok = uname(&uts) != -1;
842 if ( ok )
843 {
e90c1d2a 844 wxStrncpy(buf, wxConvertMB2WX(uts.nodename), sz - 1);
223d09f6 845 buf[sz] = wxT('\0');
518b5d2f
VZ
846 }
847#elif defined(HAVE_GETHOSTNAME)
848 bool ok = gethostname(buf, sz) != -1;
0fb67cd1 849#else // no uname, no gethostname
223d09f6 850 wxFAIL_MSG(wxT("don't know host name for this machine"));
518b5d2f
VZ
851
852 bool ok = FALSE;
0fb67cd1 853#endif // uname/gethostname
518b5d2f
VZ
854
855 if ( !ok )
856 {
857 wxLogSysError(_("Cannot get the hostname"));
858 }
859
860 return ok;
861}
862
05079acc 863bool wxGetHostName(wxChar *buf, int sz)
0fb67cd1
VZ
864{
865 bool ok = wxGetHostNameInternal(buf, sz);
866
867 if ( ok )
868 {
869 // BSD systems return the FQDN, we only want the hostname, so extract
870 // it (we consider that dots are domain separators)
223d09f6 871 wxChar *dot = wxStrchr(buf, wxT('.'));
0fb67cd1
VZ
872 if ( dot )
873 {
874 // nuke it
223d09f6 875 *dot = wxT('\0');
0fb67cd1
VZ
876 }
877 }
878
879 return ok;
880}
881
05079acc 882bool wxGetFullHostName(wxChar *buf, int sz)
0fb67cd1
VZ
883{
884 bool ok = wxGetHostNameInternal(buf, sz);
885
886 if ( ok )
887 {
223d09f6 888 if ( !wxStrchr(buf, wxT('.')) )
0fb67cd1 889 {
e90c1d2a 890 struct hostent *host = gethostbyname(wxConvertWX2MB(buf));
0fb67cd1
VZ
891 if ( !host )
892 {
893 wxLogSysError(_("Cannot get the official hostname"));
894
895 ok = FALSE;
896 }
897 else
898 {
899 // the canonical name
e90c1d2a 900 wxStrncpy(buf, wxConvertMB2WX(host->h_name), sz);
0fb67cd1
VZ
901 }
902 }
903 //else: it's already a FQDN (BSD behaves this way)
904 }
905
906 return ok;
907}
908
05079acc 909bool wxGetUserId(wxChar *buf, int sz)
518b5d2f
VZ
910{
911 struct passwd *who;
912
223d09f6 913 *buf = wxT('\0');
518b5d2f
VZ
914 if ((who = getpwuid(getuid ())) != NULL)
915 {
e90c1d2a 916 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
518b5d2f
VZ
917 return TRUE;
918 }
919
920 return FALSE;
921}
922
05079acc 923bool wxGetUserName(wxChar *buf, int sz)
518b5d2f
VZ
924{
925 struct passwd *who;
518b5d2f 926
223d09f6 927 *buf = wxT('\0');
b12915c1
VZ
928 if ((who = getpwuid (getuid ())) != NULL)
929 {
930 // pw_gecos field in struct passwd is not standard
bd3277fe 931#ifdef HAVE_PW_GECOS
b12915c1 932 char *comma = strchr(who->pw_gecos, ',');
518b5d2f
VZ
933 if (comma)
934 *comma = '\0'; // cut off non-name comment fields
e90c1d2a 935 wxStrncpy (buf, wxConvertMB2WX(who->pw_gecos), sz - 1);
b12915c1 936#else // !HAVE_PW_GECOS
0fcdf6dc 937 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
b12915c1 938#endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
518b5d2f
VZ
939 return TRUE;
940 }
941
942 return FALSE;
943}
944
bdc72a22
VZ
945wxString wxGetOsDescription()
946{
947#ifndef WXWIN_OS_DESCRIPTION
948 #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
949#else
950 return WXWIN_OS_DESCRIPTION;
951#endif
952}
953
bd3277fe
VZ
954// this function returns the GUI toolkit version in GUI programs, but OS
955// version in non-GUI ones
956#if !wxUSE_GUI
957
958int wxGetOsVersion(int *majorVsn, int *minorVsn)
959{
960 int major, minor;
961 char name[256];
962
963 if ( sscanf(WXWIN_OS_DESCRIPTION, "%s %d.%d", name, &major, &minor) != 3 )
964 {
965 // unreckognized uname string format
966 major = minor = -1;
967 }
968
969 if ( majorVsn )
970 *majorVsn = major;
971 if ( minorVsn )
972 *minorVsn = minor;
973
974 return wxUNIX;
975}
976
977#endif // !wxUSE_GUI
978
979long wxGetFreeMemory()
980{
981#if defined(__LINUX__)
982 // get it from /proc/meminfo
983 FILE *fp = fopen("/proc/meminfo", "r");
984 if ( fp )
985 {
986 long memFree = -1;
987
988 char buf[1024];
989 if ( fgets(buf, WXSIZEOF(buf), fp) && fgets(buf, WXSIZEOF(buf), fp) )
990 {
991 long memTotal, memUsed;
992 sscanf(buf, "Mem: %ld %ld %ld", &memTotal, &memUsed, &memFree);
993 }
994
995 fclose(fp);
996
997 return memFree;
998 }
999#elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES)
1000 return sysconf(_SC_AVPHYS_PAGES)*sysconf(_SC_PAGESIZE);
1001//#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1002#endif
1003
1004 // can't find it out
1005 return -1;
1006}
1007
7f6097f1 1008#ifndef __WXMAC__
eadd7bd2
VZ
1009bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree)
1010{
1011#ifdef HAVE_STATFS
1012
1013 struct statfs fs;
1014 if ( statfs(path, &fs) != 0 )
1015 {
1016 wxLogSysError("Failed to get file system statistics");
1017
1018 return FALSE;
1019 }
1020
1021 if ( pTotal )
1022 {
1023 *pTotal = wxLongLong(fs.f_blocks) * fs.f_bsize;
1024 }
1025
1026 if ( pFree )
1027 {
1028 *pFree = wxLongLong(fs.f_bavail) * fs.f_bsize;
1029 }
1030
1031 return TRUE;
1032#endif // HAVE_STATFS
1033
1034 return FALSE;
1035}
7f6097f1 1036#endif
eadd7bd2 1037
8fd0d89b
VZ
1038// ----------------------------------------------------------------------------
1039// env vars
1040// ----------------------------------------------------------------------------
1041
97b305b7 1042bool wxGetEnv(const wxString& var, wxString *value)
308978f6
VZ
1043{
1044 // wxGetenv is defined as getenv()
1045 wxChar *p = wxGetenv(var);
1046 if ( !p )
1047 return FALSE;
1048
1049 if ( value )
1050 {
1051 *value = p;
1052 }
1053
1054 return TRUE;
1055}
1056
8fd0d89b
VZ
1057bool wxSetEnv(const wxString& variable, const wxChar *value)
1058{
1059#if defined(HAVE_SETENV)
1060 return setenv(variable.mb_str(), value ? wxString(value).mb_str().data()
1061 : NULL, 1 /* overwrite */) == 0;
1062#elif defined(HAVE_PUTENV)
1063 wxString s = variable;
1064 if ( value )
1065 s << _T('=') << value;
1066
1067 // transform to ANSI
1068 const char *p = s.mb_str();
1069
1070 // the string will be free()d by libc
1071 char *buf = (char *)malloc(strlen(p) + 1);
1072 strcpy(buf, p);
1073
1074 return putenv(buf) == 0;
1075#else // no way to set an env var
1076 return FALSE;
1077#endif
1078}
1079
a37a5a73
VZ
1080// ----------------------------------------------------------------------------
1081// signal handling
1082// ----------------------------------------------------------------------------
1083
1084#if wxUSE_ON_FATAL_EXCEPTION
1085
1086#include <signal.h>
1087
f6bcfd97 1088static void wxFatalSignalHandler(wxTYPE_SA_HANDLER)
a37a5a73
VZ
1089{
1090 if ( wxTheApp )
1091 {
1092 // give the user a chance to do something special about this
1093 wxTheApp->OnFatalException();
1094 }
1095
1096 abort();
1097}
1098
1099bool wxHandleFatalExceptions(bool doit)
1100{
1101 // old sig handlers
1102 static bool s_savedHandlers = FALSE;
1103 static struct sigaction s_handlerFPE,
1104 s_handlerILL,
1105 s_handlerBUS,
1106 s_handlerSEGV;
1107
1108 bool ok = TRUE;
1109 if ( doit && !s_savedHandlers )
1110 {
1111 // install the signal handler
1112 struct sigaction act;
1113
1114 // some systems extend it with non std fields, so zero everything
1115 memset(&act, 0, sizeof(act));
1116
1117 act.sa_handler = wxFatalSignalHandler;
1118 sigemptyset(&act.sa_mask);
1119 act.sa_flags = 0;
1120
1121 ok &= sigaction(SIGFPE, &act, &s_handlerFPE) == 0;
1122 ok &= sigaction(SIGILL, &act, &s_handlerILL) == 0;
1123 ok &= sigaction(SIGBUS, &act, &s_handlerBUS) == 0;
1124 ok &= sigaction(SIGSEGV, &act, &s_handlerSEGV) == 0;
1125 if ( !ok )
1126 {
1127 wxLogDebug(_T("Failed to install our signal handler."));
1128 }
1129
1130 s_savedHandlers = TRUE;
1131 }
1132 else if ( s_savedHandlers )
1133 {
1134 // uninstall the signal handler
1135 ok &= sigaction(SIGFPE, &s_handlerFPE, NULL) == 0;
1136 ok &= sigaction(SIGILL, &s_handlerILL, NULL) == 0;
1137 ok &= sigaction(SIGBUS, &s_handlerBUS, NULL) == 0;
1138 ok &= sigaction(SIGSEGV, &s_handlerSEGV, NULL) == 0;
1139 if ( !ok )
1140 {
1141 wxLogDebug(_T("Failed to uninstall our signal handler."));
1142 }
1143
1144 s_savedHandlers = FALSE;
1145 }
1146 //else: nothing to do
1147
1148 return ok;
1149}
1150
1151#endif // wxUSE_ON_FATAL_EXCEPTION
1152
518b5d2f
VZ
1153// ----------------------------------------------------------------------------
1154// error and debug output routines (deprecated, use wxLog)
1155// ----------------------------------------------------------------------------
1156
1157void wxDebugMsg( const char *format, ... )
1158{
1159 va_list ap;
1160 va_start( ap, format );
1161 vfprintf( stderr, format, ap );
1162 fflush( stderr );
1163 va_end(ap);
1164}
1165
1166void wxError( const wxString &msg, const wxString &title )
1167{
05079acc 1168 wxFprintf( stderr, _("Error ") );
223d09f6
KB
1169 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
1170 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
1171 wxFprintf( stderr, wxT(".\n") );
518b5d2f
VZ
1172}
1173
1174void wxFatalError( const wxString &msg, const wxString &title )
1175{
05079acc 1176 wxFprintf( stderr, _("Error ") );
223d09f6
KB
1177 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
1178 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
1179 wxFprintf( stderr, wxT(".\n") );
518b5d2f
VZ
1180 exit(3); // the same exit code as for abort()
1181}
93ccaed8 1182