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