1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: generic Unix implementation of many wx functions
4 // Author: Vadim Zeitlin
6 // Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
19 #include "wx/string.h"
26 #include "wx/process.h"
27 #include "wx/thread.h"
29 #include "wx/stream.h"
36 #include "wx/unix/execute.h"
39 // SGI signal.h defines signal handler arguments differently depending on
40 // whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it
41 #if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS)
42 #define _LANGUAGE_C_PLUS_PLUS 1
49 #include <sys/types.h>
56 #include <fcntl.h> // for O_WRONLY and friends
57 #include <time.h> // nanosleep() and/or usleep()
58 #include <ctype.h> // isspace()
59 #include <sys/time.h> // needed for FD_SETSIZE
62 #include <sys/utsname.h> // for uname()
65 // ----------------------------------------------------------------------------
66 // conditional compilation
67 // ----------------------------------------------------------------------------
69 // many versions of Unices have this function, but it is not defined in system
70 // headers - please add your system here if it is the case for your OS.
71 // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
72 #if !defined(HAVE_USLEEP) && \
73 (defined(__SUN__) && !defined(__SunOs_5_6) && \
74 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
75 defined(__osf__) || defined(__EMX__)
79 int usleep(unsigned int usec
);
82 /* I copied this from the XFree86 diffs. AV. */
83 #define INCL_DOSPROCESS
85 inline void usleep(unsigned long delay
)
87 DosSleep(delay
? (delay
/1000l) : 1l);
90 void usleep(unsigned long usec
);
92 #endif // Sun/EMX/Something else
96 #endif // Unices without usleep()
98 // ============================================================================
100 // ============================================================================
102 // ----------------------------------------------------------------------------
104 // ----------------------------------------------------------------------------
106 void wxSleep(int nSecs
)
111 void wxUsleep(unsigned long milliseconds
)
113 #if defined(HAVE_NANOSLEEP)
115 tmReq
.tv_sec
= (time_t)(milliseconds
/ 1000);
116 tmReq
.tv_nsec
= (milliseconds
% 1000) * 1000 * 1000;
118 // we're not interested in remaining time nor in return value
119 (void)nanosleep(&tmReq
, (timespec
*)NULL
);
120 #elif defined(HAVE_USLEEP)
121 // uncomment this if you feel brave or if you are sure that your version
122 // of Solaris has a safe usleep() function but please notice that usleep()
123 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
124 // documented as MT-Safe
125 #if defined(__SUN__) && wxUSE_THREADS
126 #error "usleep() cannot be used in MT programs under Solaris."
129 usleep(milliseconds
* 1000); // usleep(3) wants microseconds
130 #elif defined(HAVE_SLEEP)
131 // under BeOS sleep() takes seconds (what about other platforms, if any?)
132 sleep(milliseconds
* 1000);
133 #else // !sleep function
134 #error "usleep() or nanosleep() function required for wxUsleep"
135 #endif // sleep function
138 // ----------------------------------------------------------------------------
139 // process management
140 // ----------------------------------------------------------------------------
142 int wxKill(long pid
, wxSignal sig
, wxKillError
*rc
)
144 int err
= kill((pid_t
)pid
, (int)sig
);
154 *rc
= wxKILL_BAD_SIGNAL
;
158 *rc
= wxKILL_ACCESS_DENIED
;
162 *rc
= wxKILL_NO_PROCESS
;
166 // this goes against Unix98 docs so log it
167 wxLogDebug(_T("unexpected kill(2) return value %d"), err
);
177 #define WXEXECUTE_NARGS 127
179 long wxExecute( const wxString
& command
, bool sync
, wxProcess
*process
)
181 wxCHECK_MSG( !command
.IsEmpty(), 0, wxT("can't exec empty command") );
184 wxChar
*argv
[WXEXECUTE_NARGS
];
186 const wxChar
*cptr
= command
.c_str();
187 wxChar quotechar
= wxT('\0'); // is arg quoted?
188 bool escaped
= FALSE
;
190 // split the command line in arguments
194 quotechar
= wxT('\0');
196 // eat leading whitespace:
197 while ( wxIsspace(*cptr
) )
200 if ( *cptr
== wxT('\'') || *cptr
== wxT('"') )
205 if ( *cptr
== wxT('\\') && ! escaped
)
212 // all other characters:
216 // have we reached the end of the argument?
217 if ( (*cptr
== quotechar
&& ! escaped
)
218 || (quotechar
== wxT('\0') && wxIsspace(*cptr
))
219 || *cptr
== wxT('\0') )
221 wxASSERT_MSG( argc
< WXEXECUTE_NARGS
,
222 wxT("too many arguments in wxExecute") );
224 argv
[argc
] = new wxChar
[argument
.length() + 1];
225 wxStrcpy(argv
[argc
], argument
.c_str());
228 // if not at end of buffer, swallow last character:
232 break; // done with this one, start over
238 // do execute the command
239 long lRc
= wxExecute(argv
, sync
, process
);
244 delete [] argv
[argc
++];
249 // ----------------------------------------------------------------------------
251 // ----------------------------------------------------------------------------
253 static wxString
wxMakeShellCommand(const wxString
& command
)
258 // just an interactive shell
263 // execute command in a shell
264 cmd
<< _T("/bin/sh -c '") << command
<< _T('\'');
270 bool wxShell(const wxString
& command
)
272 return wxExecute(wxMakeShellCommand(command
), TRUE
/* sync */) == 0;
275 bool wxShell(const wxString
& command
, wxArrayString
& output
)
277 wxCHECK_MSG( !!command
, FALSE
, _T("can't exec shell non interactively") );
279 return wxExecute(wxMakeShellCommand(command
), output
);
284 void wxHandleProcessTermination(wxEndProcessData
*proc_data
)
286 int pid
= (proc_data
->pid
> 0) ? proc_data
->pid
: -(proc_data
->pid
);
288 // waitpid is POSIX so should be available everywhere, however on older
289 // systems wait() might be used instead in a loop (until the right pid
294 // wait for child termination and if waitpid() was interrupted, try again
297 rc
= waitpid(pid
, &status
, 0);
299 while ( rc
== -1 && errno
== EINTR
);
301 // notify user about termination if required
302 if ( proc_data
->process
)
304 proc_data
->process
->OnTerminate
307 (rc
== 0) && WIFEXITED(status
)
308 ? WEXITSTATUS(status
)
313 if ( proc_data
->pid
> 0 )
319 // wxExecute() will know about it
320 proc_data
->exitcode
= status
;
328 // ----------------------------------------------------------------------------
329 // wxStream classes to support IO redirection in wxExecute
330 // ----------------------------------------------------------------------------
334 class wxProcessFileInputStream
: public wxInputStream
337 wxProcessFileInputStream(int fd
) { m_fd
= fd
; }
338 ~wxProcessFileInputStream() { close(m_fd
); }
340 virtual bool Eof() const;
343 size_t OnSysRead(void *buffer
, size_t bufsize
);
349 class wxProcessFileOutputStream
: public wxOutputStream
352 wxProcessFileOutputStream(int fd
) { m_fd
= fd
; }
353 ~wxProcessFileOutputStream() { close(m_fd
); }
356 size_t OnSysWrite(const void *buffer
, size_t bufsize
);
362 bool wxProcessFileInputStream::Eof() const
364 if ( m_lasterror
== wxSTREAM_EOF
)
367 // check if there is any input available
374 FD_SET(m_fd
, &readfds
);
375 switch ( select(m_fd
+ 1, &readfds
, NULL
, NULL
, &tv
) )
378 wxLogSysError(_("Impossible to get child process input"));
385 wxFAIL_MSG(_T("unexpected select() return value"));
386 // still fall through
389 // input available: check if there is any
390 return wxInputStream::Eof();
394 size_t wxProcessFileInputStream::OnSysRead(void *buffer
, size_t bufsize
)
396 int ret
= read(m_fd
, buffer
, bufsize
);
399 m_lasterror
= wxSTREAM_EOF
;
401 else if ( ret
== -1 )
403 m_lasterror
= wxSTREAM_READ_ERROR
;
408 m_lasterror
= wxSTREAM_NOERROR
;
414 size_t wxProcessFileOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
416 int ret
= write(m_fd
, buffer
, bufsize
);
419 m_lasterror
= wxSTREAM_WRITE_ERROR
;
424 m_lasterror
= wxSTREAM_NOERROR
;
430 // ----------------------------------------------------------------------------
431 // wxStreamTempBuffer
432 // ----------------------------------------------------------------------------
435 Extract of a mail to wx-users to give the context of the problem we are
436 trying to solve here:
438 MC> If I run the command:
439 MC> find . -name "*.h" -exec grep linux {} \;
440 MC> in the exec sample synchronously from the 'Capture command output'
441 MC> menu, wxExecute never returns. I have to xkill it. Has anyone
442 MC> else encountered this?
444 Yes, I can reproduce it too.
446 I even think I understand why it happens: before launching the external
447 command we set up a pipe with a valid file descriptor on the reading side
448 when the output is redirected. So the subprocess happily writes to it ...
449 until the pipe buffer (which is usually quite big on Unix, I think the
450 default is 4Mb) is full. Then the writing process stops and waits until we
451 read some data from the pipe to be able to continue writing to it but we
452 never do it because we wait until it terminates to start reading and so we
453 have a classical deadlock.
455 Here is the fix: we now read the output as soon as it appears into a temp
456 buffer (wxStreamTempBuffer object) and later just stuff it back into the
457 stream when the process terminates. See supporting code in wxExecute()
461 class wxStreamTempBuffer
464 wxStreamTempBuffer();
466 // call to associate a stream with this buffer, otherwise nothing happens
468 void Init(wxInputStream
*stream
);
470 // check for input on our stream and cache it in our buffer if any
473 ~wxStreamTempBuffer();
476 // the stream we're buffering, if NULL we don't do anything at all
477 wxInputStream
*m_stream
;
479 // the buffer of size m_size (NULL if m_size == 0)
482 // the size of the buffer
486 wxStreamTempBuffer::wxStreamTempBuffer()
493 void wxStreamTempBuffer::Init(wxInputStream
*stream
)
498 void wxStreamTempBuffer::Update()
500 if ( m_stream
&& !m_stream
->Eof() )
502 // realloc in blocks of 1Kb - surely not the best strategy but which
504 static const size_t incSize
= 1024;
506 void *buf
= realloc(m_buffer
, m_size
+ incSize
);
509 // don't read any more, we don't have enough memory to do it
512 else // got memory for the buffer
515 m_stream
->Read((char *)m_buffer
+ m_size
, incSize
);
521 wxStreamTempBuffer::~wxStreamTempBuffer()
525 m_stream
->Ungetch(m_buffer
, m_size
);
530 #endif // wxUSE_STREAMS
532 long wxExecute(wxChar
**argv
,
536 // for the sync execution, we return -1 to indicate failure, but for async
537 // case we return 0 which is never a valid PID
539 // we define this as a macro, not a variable, to avoid compiler warnings
540 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
541 #define ERROR_RETURN_CODE ((sync) ? -1 : 0)
543 wxCHECK_MSG( *argv
, ERROR_RETURN_CODE
, wxT("can't exec empty command") );
547 char *mb_argv
[WXEXECUTE_NARGS
];
549 while (argv
[mb_argc
])
551 wxWX2MBbuf mb_arg
= wxConvertWX2MB(argv
[mb_argc
]);
552 mb_argv
[mb_argc
] = strdup(mb_arg
);
555 mb_argv
[mb_argc
] = (char *) NULL
;
557 // this macro will free memory we used above
558 #define ARGS_CLEANUP \
559 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
560 free(mb_argv[mb_argc])
562 // no need for cleanup
565 wxChar
**mb_argv
= argv
;
566 #endif // Unicode/ANSI
570 int end_proc_detect
[2];
571 if ( pipe(end_proc_detect
) == -1 )
573 wxLogSysError( _("Pipe creation failed") );
574 wxLogError( _("Failed to execute '%s'\n"), *argv
);
578 return ERROR_RETURN_CODE
;
582 // pipes for inter process communication
583 int pipeIn
[2], // stdin
584 pipeOut
[2], // stdout
585 pipeErr
[2]; // stderr
587 pipeIn
[0] = pipeIn
[1] =
588 pipeOut
[0] = pipeOut
[1] =
589 pipeErr
[0] = pipeErr
[1] = -1;
591 if ( process
&& process
->IsRedirected() )
593 if ( pipe(pipeIn
) == -1 || pipe(pipeOut
) == -1 || pipe(pipeErr
) == -1 )
596 // free previously allocated resources
597 close(end_proc_detect
[0]);
598 close(end_proc_detect
[1]);
601 wxLogSysError( _("Pipe creation failed") );
602 wxLogError( _("Failed to execute '%s'\n"), *argv
);
606 return ERROR_RETURN_CODE
;
617 if ( pid
== -1 ) // error?
620 close(end_proc_detect
[0]);
621 close(end_proc_detect
[1]);
630 wxLogSysError( _("Fork failed") );
634 return ERROR_RETURN_CODE
;
636 else if ( pid
== 0 ) // we're in child
639 close(end_proc_detect
[0]); // close reading side
642 // These lines close the open file descriptors to to avoid any
643 // input/output which might block the process or irritate the user. If
644 // one wants proper IO for the subprocess, the right thing to do is to
645 // start an xterm executing it.
648 for ( int fd
= 0; fd
< FD_SETSIZE
; fd
++ )
650 if ( fd
== pipeIn
[0] || fd
== pipeOut
[1] || fd
== pipeErr
[1]
652 || fd
== end_proc_detect
[1]
656 // don't close this one, we still need it
660 // leave stderr opened too, it won't do any hurm
661 if ( fd
!= STDERR_FILENO
)
666 // redirect stdio, stdout and stderr
667 if ( pipeIn
[0] != -1 )
669 if ( dup2(pipeIn
[0], STDIN_FILENO
) == -1 ||
670 dup2(pipeOut
[1], STDOUT_FILENO
) == -1 ||
671 dup2(pipeErr
[1], STDERR_FILENO
) == -1 )
673 wxLogSysError(_("Failed to redirect child process input/output"));
681 execvp (*mb_argv
, mb_argv
);
683 // there is no return after successful exec()
686 // some compilers complain about missing return - of course, they
687 // should know that exit() doesn't return but what else can we do if
689 #if defined(__VMS) || defined(__INTEL_COMPILER)
693 else // we're in parent
697 // pipe initialization: construction of the wxStreams
699 wxStreamTempBuffer bufIn
, bufErr
;
700 #endif // wxUSE_STREAMS
702 if ( process
&& process
->IsRedirected() )
705 // in/out for subprocess correspond to our out/in
706 wxOutputStream
*outStream
= new wxProcessFileOutputStream(pipeIn
[1]);
707 wxInputStream
*inStream
= new wxProcessFileInputStream(pipeOut
[0]);
708 wxInputStream
*errStream
= new wxProcessFileInputStream(pipeErr
[0]);
710 process
->SetPipeStreams(inStream
, outStream
, errStream
);
712 bufIn
.Init(inStream
);
713 bufErr
.Init(inStream
);
714 #endif // wxUSE_STREAMS
716 close(pipeIn
[0]); // close reading side
717 close(pipeOut
[1]); // close writing side
718 close(pipeErr
[1]); // close writing side
721 #if wxUSE_GUI && !defined(__WXMICROWIN__)
722 wxEndProcessData
*data
= new wxEndProcessData
;
726 // we may have process for capturing the program output, but it's
727 // not used in wxEndProcessData in the case of sync execution
728 data
->process
= NULL
;
730 // sync execution: indicate it by negating the pid
732 data
->tag
= wxAddProcessCallback(data
, end_proc_detect
[0]);
734 close(end_proc_detect
[1]); // close writing side
739 // data->pid will be set to 0 from GTK_EndProcessDetector when the
740 // process terminates
741 while ( data
->pid
!= 0 )
746 #endif // wxUSE_STREAMS
748 // give GTK+ a chance to call GTK_EndProcessDetector here and
749 // also repaint the GUI
753 int exitcode
= data
->exitcode
;
759 else // async execution
761 // async execution, nothing special to do - caller will be
762 // notified about the process termination if process != NULL, data
763 // will be deleted in GTK_EndProcessDetector
764 data
->process
= process
;
766 data
->tag
= wxAddProcessCallback(data
, end_proc_detect
[0]);
768 close(end_proc_detect
[1]); // close writing side
773 wxASSERT_MSG( sync
, wxT("async execution not supported yet") );
776 if ( waitpid(pid
, &exitcode
, 0) == -1 || !WIFEXITED(exitcode
) )
778 wxLogSysError(_("Waiting for subprocess termination failed"));
786 #undef ERROR_RETURN_CODE
789 // ----------------------------------------------------------------------------
790 // file and directory functions
791 // ----------------------------------------------------------------------------
793 const wxChar
* wxGetHomeDir( wxString
*home
)
795 *home
= wxGetUserHome( wxString() );
797 if ( home
->IsEmpty() )
801 if ( tmp
.Last() != wxT(']'))
802 if ( tmp
.Last() != wxT('/')) *home
<< wxT('/');
804 return home
->c_str();
808 const wxMB2WXbuf
wxGetUserHome( const wxString
&user
)
809 #else // just for binary compatibility -- there is no 'const' here
810 char *wxGetUserHome( const wxString
&user
)
813 struct passwd
*who
= (struct passwd
*) NULL
;
819 if ((ptr
= wxGetenv(wxT("HOME"))) != NULL
)
823 if ((ptr
= wxGetenv(wxT("USER"))) != NULL
|| (ptr
= wxGetenv(wxT("LOGNAME"))) != NULL
)
825 who
= getpwnam(wxConvertWX2MB(ptr
));
828 // We now make sure the the user exists!
831 who
= getpwuid(getuid());
836 who
= getpwnam (user
.mb_str());
839 return wxConvertMB2WX(who
? who
->pw_dir
: 0);
842 // ----------------------------------------------------------------------------
843 // network and user id routines
844 // ----------------------------------------------------------------------------
846 // retrieve either the hostname or FQDN depending on platform (caller must
847 // check whether it's one or the other, this is why this function is for
849 static bool wxGetHostNameInternal(wxChar
*buf
, int sz
)
851 wxCHECK_MSG( buf
, FALSE
, wxT("NULL pointer in wxGetHostNameInternal") );
855 // we're using uname() which is POSIX instead of less standard sysinfo()
856 #if defined(HAVE_UNAME)
858 bool ok
= uname(&uts
) != -1;
861 wxStrncpy(buf
, wxConvertMB2WX(uts
.nodename
), sz
- 1);
864 #elif defined(HAVE_GETHOSTNAME)
865 bool ok
= gethostname(buf
, sz
) != -1;
866 #else // no uname, no gethostname
867 wxFAIL_MSG(wxT("don't know host name for this machine"));
870 #endif // uname/gethostname
874 wxLogSysError(_("Cannot get the hostname"));
880 bool wxGetHostName(wxChar
*buf
, int sz
)
882 bool ok
= wxGetHostNameInternal(buf
, sz
);
886 // BSD systems return the FQDN, we only want the hostname, so extract
887 // it (we consider that dots are domain separators)
888 wxChar
*dot
= wxStrchr(buf
, wxT('.'));
899 bool wxGetFullHostName(wxChar
*buf
, int sz
)
901 bool ok
= wxGetHostNameInternal(buf
, sz
);
905 if ( !wxStrchr(buf
, wxT('.')) )
907 struct hostent
*host
= gethostbyname(wxConvertWX2MB(buf
));
910 wxLogSysError(_("Cannot get the official hostname"));
916 // the canonical name
917 wxStrncpy(buf
, wxConvertMB2WX(host
->h_name
), sz
);
920 //else: it's already a FQDN (BSD behaves this way)
926 bool wxGetUserId(wxChar
*buf
, int sz
)
931 if ((who
= getpwuid(getuid ())) != NULL
)
933 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz
- 1);
940 bool wxGetUserName(wxChar
*buf
, int sz
)
945 if ((who
= getpwuid (getuid ())) != NULL
)
947 // pw_gecos field in struct passwd is not standard
949 char *comma
= strchr(who
->pw_gecos
, ',');
951 *comma
= '\0'; // cut off non-name comment fields
952 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_gecos
), sz
- 1);
953 #else // !HAVE_PW_GECOS
954 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz
- 1);
955 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
962 wxString
wxGetOsDescription()
964 #ifndef WXWIN_OS_DESCRIPTION
965 #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
967 return WXWIN_OS_DESCRIPTION
;
971 // this function returns the GUI toolkit version in GUI programs, but OS
972 // version in non-GUI ones
975 int wxGetOsVersion(int *majorVsn
, int *minorVsn
)
980 if ( sscanf(WXWIN_OS_DESCRIPTION
, "%s %d.%d", name
, &major
, &minor
) != 3 )
982 // unreckognized uname string format
996 long wxGetFreeMemory()
998 #if defined(__LINUX__)
999 // get it from /proc/meminfo
1000 FILE *fp
= fopen("/proc/meminfo", "r");
1006 if ( fgets(buf
, WXSIZEOF(buf
), fp
) && fgets(buf
, WXSIZEOF(buf
), fp
) )
1008 long memTotal
, memUsed
;
1009 sscanf(buf
, "Mem: %ld %ld %ld", &memTotal
, &memUsed
, &memFree
);
1016 #elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES)
1017 return sysconf(_SC_AVPHYS_PAGES
)*sysconf(_SC_PAGESIZE
);
1018 //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1021 // can't find it out
1025 bool wxGetDiskSpace(const wxString
& path
, wxLongLong
*pTotal
, wxLongLong
*pFree
)
1030 if ( statfs(path
, &fs
) != 0 )
1032 wxLogSysError("Failed to get file system statistics");
1039 *pTotal
= wxLongLong(fs
.f_blocks
) * fs
.f_bsize
;
1044 *pFree
= wxLongLong(fs
.f_bavail
) * fs
.f_bsize
;
1048 #endif // HAVE_STATFS
1053 // ----------------------------------------------------------------------------
1055 // ----------------------------------------------------------------------------
1057 bool wxGetEnv(const wxString
& var
, wxString
*value
)
1059 // wxGetenv is defined as getenv()
1060 wxChar
*p
= wxGetenv(var
);
1072 bool wxSetEnv(const wxString
& variable
, const wxChar
*value
)
1074 #if defined(HAVE_SETENV)
1075 return setenv(variable
.mb_str(), value
? wxString(value
).mb_str().data()
1076 : NULL
, 1 /* overwrite */) == 0;
1077 #elif defined(HAVE_PUTENV)
1078 wxString s
= variable
;
1080 s
<< _T('=') << value
;
1082 // transform to ANSI
1083 const char *p
= s
.mb_str();
1085 // the string will be free()d by libc
1086 char *buf
= (char *)malloc(strlen(p
) + 1);
1089 return putenv(buf
) == 0;
1090 #else // no way to set an env var
1095 // ----------------------------------------------------------------------------
1097 // ----------------------------------------------------------------------------
1099 #if wxUSE_ON_FATAL_EXCEPTION
1103 static void wxFatalSignalHandler(wxTYPE_SA_HANDLER
)
1107 // give the user a chance to do something special about this
1108 wxTheApp
->OnFatalException();
1114 bool wxHandleFatalExceptions(bool doit
)
1117 static bool s_savedHandlers
= FALSE
;
1118 static struct sigaction s_handlerFPE
,
1124 if ( doit
&& !s_savedHandlers
)
1126 // install the signal handler
1127 struct sigaction act
;
1129 // some systems extend it with non std fields, so zero everything
1130 memset(&act
, 0, sizeof(act
));
1132 act
.sa_handler
= wxFatalSignalHandler
;
1133 sigemptyset(&act
.sa_mask
);
1136 ok
&= sigaction(SIGFPE
, &act
, &s_handlerFPE
) == 0;
1137 ok
&= sigaction(SIGILL
, &act
, &s_handlerILL
) == 0;
1138 ok
&= sigaction(SIGBUS
, &act
, &s_handlerBUS
) == 0;
1139 ok
&= sigaction(SIGSEGV
, &act
, &s_handlerSEGV
) == 0;
1142 wxLogDebug(_T("Failed to install our signal handler."));
1145 s_savedHandlers
= TRUE
;
1147 else if ( s_savedHandlers
)
1149 // uninstall the signal handler
1150 ok
&= sigaction(SIGFPE
, &s_handlerFPE
, NULL
) == 0;
1151 ok
&= sigaction(SIGILL
, &s_handlerILL
, NULL
) == 0;
1152 ok
&= sigaction(SIGBUS
, &s_handlerBUS
, NULL
) == 0;
1153 ok
&= sigaction(SIGSEGV
, &s_handlerSEGV
, NULL
) == 0;
1156 wxLogDebug(_T("Failed to uninstall our signal handler."));
1159 s_savedHandlers
= FALSE
;
1161 //else: nothing to do
1166 #endif // wxUSE_ON_FATAL_EXCEPTION
1168 // ----------------------------------------------------------------------------
1169 // error and debug output routines (deprecated, use wxLog)
1170 // ----------------------------------------------------------------------------
1172 void wxDebugMsg( const char *format
, ... )
1175 va_start( ap
, format
);
1176 vfprintf( stderr
, format
, ap
);
1181 void wxError( const wxString
&msg
, const wxString
&title
)
1183 wxFprintf( stderr
, _("Error ") );
1184 if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) );
1185 if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) );
1186 wxFprintf( stderr
, wxT(".\n") );
1189 void wxFatalError( const wxString
&msg
, const wxString
&title
)
1191 wxFprintf( stderr
, _("Error ") );
1192 if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) );
1193 if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) );
1194 wxFprintf( stderr
, wxT(".\n") );
1195 exit(3); // the same exit code as for abort()