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"
33 # include <sys/param.h>
34 # include <sys/mount.h>
41 #include "wx/unix/execute.h"
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
54 #include <sys/types.h>
61 #include <fcntl.h> // for O_WRONLY and friends
62 #include <time.h> // nanosleep() and/or usleep()
63 #include <ctype.h> // isspace()
64 #include <sys/time.h> // needed for FD_SETSIZE
67 #include <sys/utsname.h> // for uname()
70 // ----------------------------------------------------------------------------
71 // conditional compilation
72 // ----------------------------------------------------------------------------
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.
77 #if !defined(HAVE_USLEEP) && \
78 (defined(__SUN__) && !defined(__SunOs_5_6) && \
79 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
80 defined(__osf__) || defined(__EMX__)
84 int usleep(unsigned int usec
);
87 /* I copied this from the XFree86 diffs. AV. */
88 #define INCL_DOSPROCESS
90 inline void usleep(unsigned long delay
)
92 DosSleep(delay
? (delay
/1000l) : 1l);
95 void usleep(unsigned long usec
);
97 #endif // Sun/EMX/Something else
100 #define HAVE_USLEEP 1
101 #endif // Unices without usleep()
103 // ============================================================================
105 // ============================================================================
107 // ----------------------------------------------------------------------------
109 // ----------------------------------------------------------------------------
111 void wxSleep(int nSecs
)
116 void wxUsleep(unsigned long milliseconds
)
118 #if defined(HAVE_NANOSLEEP)
120 tmReq
.tv_sec
= (time_t)(milliseconds
/ 1000);
121 tmReq
.tv_nsec
= (milliseconds
% 1000) * 1000 * 1000;
123 // we're not interested in remaining time nor in return value
124 (void)nanosleep(&tmReq
, (timespec
*)NULL
);
125 #elif defined(HAVE_USLEEP)
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
130 #if defined(__SUN__) && wxUSE_THREADS
131 #error "usleep() cannot be used in MT programs under Solaris."
134 usleep(milliseconds
* 1000); // usleep(3) wants microseconds
135 #elif defined(HAVE_SLEEP)
136 // under BeOS sleep() takes seconds (what about other platforms, if any?)
137 sleep(milliseconds
* 1000);
138 #else // !sleep function
139 #error "usleep() or nanosleep() function required for wxUsleep"
140 #endif // sleep function
143 // ----------------------------------------------------------------------------
144 // process management
145 // ----------------------------------------------------------------------------
147 int wxKill(long pid
, wxSignal sig
, wxKillError
*rc
)
149 int err
= kill((pid_t
)pid
, (int)sig
);
159 *rc
= wxKILL_BAD_SIGNAL
;
163 *rc
= wxKILL_ACCESS_DENIED
;
167 *rc
= wxKILL_NO_PROCESS
;
171 // this goes against Unix98 docs so log it
172 wxLogDebug(_T("unexpected kill(2) return value %d"), err
);
182 #define WXEXECUTE_NARGS 127
184 long wxExecute( const wxString
& command
, bool sync
, wxProcess
*process
)
186 wxCHECK_MSG( !command
.IsEmpty(), 0, wxT("can't exec empty command") );
189 wxChar
*argv
[WXEXECUTE_NARGS
];
191 const wxChar
*cptr
= command
.c_str();
192 wxChar quotechar
= wxT('\0'); // is arg quoted?
193 bool escaped
= FALSE
;
195 // split the command line in arguments
199 quotechar
= wxT('\0');
201 // eat leading whitespace:
202 while ( wxIsspace(*cptr
) )
205 if ( *cptr
== wxT('\'') || *cptr
== wxT('"') )
210 if ( *cptr
== wxT('\\') && ! escaped
)
217 // all other characters:
221 // have we reached the end of the argument?
222 if ( (*cptr
== quotechar
&& ! escaped
)
223 || (quotechar
== wxT('\0') && wxIsspace(*cptr
))
224 || *cptr
== wxT('\0') )
226 wxASSERT_MSG( argc
< WXEXECUTE_NARGS
,
227 wxT("too many arguments in wxExecute") );
229 argv
[argc
] = new wxChar
[argument
.length() + 1];
230 wxStrcpy(argv
[argc
], argument
.c_str());
233 // if not at end of buffer, swallow last character:
237 break; // done with this one, start over
243 // do execute the command
244 long lRc
= wxExecute(argv
, sync
, process
);
249 delete [] argv
[argc
++];
254 // ----------------------------------------------------------------------------
256 // ----------------------------------------------------------------------------
258 static wxString
wxMakeShellCommand(const wxString
& command
)
263 // just an interactive shell
268 // execute command in a shell
269 cmd
<< _T("/bin/sh -c '") << command
<< _T('\'');
275 bool wxShell(const wxString
& command
)
277 return wxExecute(wxMakeShellCommand(command
), TRUE
/* sync */) == 0;
280 bool wxShell(const wxString
& command
, wxArrayString
& output
)
282 wxCHECK_MSG( !!command
, FALSE
, _T("can't exec shell non interactively") );
284 return wxExecute(wxMakeShellCommand(command
), output
);
289 void wxHandleProcessTermination(wxEndProcessData
*proc_data
)
291 int pid
= (proc_data
->pid
> 0) ? proc_data
->pid
: -(proc_data
->pid
);
293 // waitpid is POSIX so should be available everywhere, however on older
294 // systems wait() might be used instead in a loop (until the right pid
299 // wait for child termination and if waitpid() was interrupted, try again
302 rc
= waitpid(pid
, &status
, 0);
304 while ( rc
== -1 && errno
== EINTR
);
306 // notify user about termination if required
307 if ( proc_data
->process
)
309 proc_data
->process
->OnTerminate
312 (rc
== 0) && WIFEXITED(status
)
313 ? WEXITSTATUS(status
)
318 if ( proc_data
->pid
> 0 )
324 // wxExecute() will know about it
325 proc_data
->exitcode
= status
;
333 // ----------------------------------------------------------------------------
334 // wxStream classes to support IO redirection in wxExecute
335 // ----------------------------------------------------------------------------
339 class wxProcessFileInputStream
: public wxInputStream
342 wxProcessFileInputStream(int fd
) { m_fd
= fd
; }
343 ~wxProcessFileInputStream() { close(m_fd
); }
345 virtual bool Eof() const;
348 size_t OnSysRead(void *buffer
, size_t bufsize
);
354 class wxProcessFileOutputStream
: public wxOutputStream
357 wxProcessFileOutputStream(int fd
) { m_fd
= fd
; }
358 ~wxProcessFileOutputStream() { close(m_fd
); }
361 size_t OnSysWrite(const void *buffer
, size_t bufsize
);
367 bool wxProcessFileInputStream::Eof() const
369 if ( m_lasterror
== wxSTREAM_EOF
)
372 // check if there is any input available
379 FD_SET(m_fd
, &readfds
);
380 switch ( select(m_fd
+ 1, &readfds
, NULL
, NULL
, &tv
) )
383 wxLogSysError(_("Impossible to get child process input"));
390 wxFAIL_MSG(_T("unexpected select() return value"));
391 // still fall through
394 // input available: check if there is any
395 return wxInputStream::Eof();
399 size_t wxProcessFileInputStream::OnSysRead(void *buffer
, size_t bufsize
)
401 int ret
= read(m_fd
, buffer
, bufsize
);
404 m_lasterror
= wxSTREAM_EOF
;
406 else if ( ret
== -1 )
408 m_lasterror
= wxSTREAM_READ_ERROR
;
413 m_lasterror
= wxSTREAM_NOERROR
;
419 size_t wxProcessFileOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
421 int ret
= write(m_fd
, buffer
, bufsize
);
424 m_lasterror
= wxSTREAM_WRITE_ERROR
;
429 m_lasterror
= wxSTREAM_NOERROR
;
435 // ----------------------------------------------------------------------------
436 // wxStreamTempBuffer
437 // ----------------------------------------------------------------------------
440 Extract of a mail to wx-users to give the context of the problem we are
441 trying to solve here:
443 MC> If I run the command:
444 MC> find . -name "*.h" -exec grep linux {} \;
445 MC> in the exec sample synchronously from the 'Capture command output'
446 MC> menu, wxExecute never returns. I have to xkill it. Has anyone
447 MC> else encountered this?
449 Yes, I can reproduce it too.
451 I even think I understand why it happens: before launching the external
452 command we set up a pipe with a valid file descriptor on the reading side
453 when the output is redirected. So the subprocess happily writes to it ...
454 until the pipe buffer (which is usually quite big on Unix, I think the
455 default is 4Mb) is full. Then the writing process stops and waits until we
456 read some data from the pipe to be able to continue writing to it but we
457 never do it because we wait until it terminates to start reading and so we
458 have a classical deadlock.
460 Here is the fix: we now read the output as soon as it appears into a temp
461 buffer (wxStreamTempBuffer object) and later just stuff it back into the
462 stream when the process terminates. See supporting code in wxExecute()
466 class wxStreamTempBuffer
469 wxStreamTempBuffer();
471 // call to associate a stream with this buffer, otherwise nothing happens
473 void Init(wxInputStream
*stream
);
475 // check for input on our stream and cache it in our buffer if any
478 ~wxStreamTempBuffer();
481 // the stream we're buffering, if NULL we don't do anything at all
482 wxInputStream
*m_stream
;
484 // the buffer of size m_size (NULL if m_size == 0)
487 // the size of the buffer
491 wxStreamTempBuffer::wxStreamTempBuffer()
498 void wxStreamTempBuffer::Init(wxInputStream
*stream
)
503 void wxStreamTempBuffer::Update()
505 if ( m_stream
&& !m_stream
->Eof() )
507 // realloc in blocks of 1Kb - surely not the best strategy but which
509 static const size_t incSize
= 1024;
511 void *buf
= realloc(m_buffer
, m_size
+ incSize
);
514 // don't read any more, we don't have enough memory to do it
517 else // got memory for the buffer
520 m_stream
->Read((char *)m_buffer
+ m_size
, incSize
);
526 wxStreamTempBuffer::~wxStreamTempBuffer()
530 m_stream
->Ungetch(m_buffer
, m_size
);
535 #endif // wxUSE_STREAMS
537 long wxExecute(wxChar
**argv
,
541 // for the sync execution, we return -1 to indicate failure, but for async
542 // case we return 0 which is never a valid PID
544 // we define this as a macro, not a variable, to avoid compiler warnings
545 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
546 #define ERROR_RETURN_CODE ((sync) ? -1 : 0)
548 wxCHECK_MSG( *argv
, ERROR_RETURN_CODE
, wxT("can't exec empty command") );
552 char *mb_argv
[WXEXECUTE_NARGS
];
554 while (argv
[mb_argc
])
556 wxWX2MBbuf mb_arg
= wxConvertWX2MB(argv
[mb_argc
]);
557 mb_argv
[mb_argc
] = strdup(mb_arg
);
560 mb_argv
[mb_argc
] = (char *) NULL
;
562 // this macro will free memory we used above
563 #define ARGS_CLEANUP \
564 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
565 free(mb_argv[mb_argc])
567 // no need for cleanup
570 wxChar
**mb_argv
= argv
;
571 #endif // Unicode/ANSI
575 int end_proc_detect
[2];
576 if ( pipe(end_proc_detect
) == -1 )
578 wxLogSysError( _("Pipe creation failed") );
579 wxLogError( _("Failed to execute '%s'\n"), *argv
);
583 return ERROR_RETURN_CODE
;
587 // pipes for inter process communication
588 int pipeIn
[2], // stdin
589 pipeOut
[2], // stdout
590 pipeErr
[2]; // stderr
592 pipeIn
[0] = pipeIn
[1] =
593 pipeOut
[0] = pipeOut
[1] =
594 pipeErr
[0] = pipeErr
[1] = -1;
596 if ( process
&& process
->IsRedirected() )
598 if ( pipe(pipeIn
) == -1 || pipe(pipeOut
) == -1 || pipe(pipeErr
) == -1 )
601 // free previously allocated resources
602 close(end_proc_detect
[0]);
603 close(end_proc_detect
[1]);
606 wxLogSysError( _("Pipe creation failed") );
607 wxLogError( _("Failed to execute '%s'\n"), *argv
);
611 return ERROR_RETURN_CODE
;
622 if ( pid
== -1 ) // error?
625 close(end_proc_detect
[0]);
626 close(end_proc_detect
[1]);
635 wxLogSysError( _("Fork failed") );
639 return ERROR_RETURN_CODE
;
641 else if ( pid
== 0 ) // we're in child
644 close(end_proc_detect
[0]); // close reading side
647 // These lines close the open file descriptors to to avoid any
648 // input/output which might block the process or irritate the user. If
649 // one wants proper IO for the subprocess, the right thing to do is to
650 // start an xterm executing it.
653 for ( int fd
= 0; fd
< FD_SETSIZE
; fd
++ )
655 if ( fd
== pipeIn
[0] || fd
== pipeOut
[1] || fd
== pipeErr
[1]
657 || fd
== end_proc_detect
[1]
661 // don't close this one, we still need it
665 // leave stderr opened too, it won't do any hurm
666 if ( fd
!= STDERR_FILENO
)
671 // redirect stdio, stdout and stderr
672 if ( pipeIn
[0] != -1 )
674 if ( dup2(pipeIn
[0], STDIN_FILENO
) == -1 ||
675 dup2(pipeOut
[1], STDOUT_FILENO
) == -1 ||
676 dup2(pipeErr
[1], STDERR_FILENO
) == -1 )
678 wxLogSysError(_("Failed to redirect child process input/output"));
686 execvp (*mb_argv
, mb_argv
);
688 // there is no return after successful exec()
691 // some compilers complain about missing return - of course, they
692 // should know that exit() doesn't return but what else can we do if
694 #if defined(__VMS) || defined(__INTEL_COMPILER)
698 else // we're in parent
702 // pipe initialization: construction of the wxStreams
704 wxStreamTempBuffer bufIn
, bufErr
;
705 #endif // wxUSE_STREAMS
707 if ( process
&& process
->IsRedirected() )
710 // in/out for subprocess correspond to our out/in
711 wxOutputStream
*outStream
= new wxProcessFileOutputStream(pipeIn
[1]);
712 wxInputStream
*inStream
= new wxProcessFileInputStream(pipeOut
[0]);
713 wxInputStream
*errStream
= new wxProcessFileInputStream(pipeErr
[0]);
715 process
->SetPipeStreams(inStream
, outStream
, errStream
);
717 bufIn
.Init(inStream
);
718 bufErr
.Init(inStream
);
719 #endif // wxUSE_STREAMS
721 close(pipeIn
[0]); // close reading side
722 close(pipeOut
[1]); // close writing side
723 close(pipeErr
[1]); // close writing side
726 #if wxUSE_GUI && !defined(__WXMICROWIN__)
727 wxEndProcessData
*data
= new wxEndProcessData
;
731 // we may have process for capturing the program output, but it's
732 // not used in wxEndProcessData in the case of sync execution
733 data
->process
= NULL
;
735 // sync execution: indicate it by negating the pid
737 data
->tag
= wxAddProcessCallback(data
, end_proc_detect
[0]);
739 close(end_proc_detect
[1]); // close writing side
744 // data->pid will be set to 0 from GTK_EndProcessDetector when the
745 // process terminates
746 while ( data
->pid
!= 0 )
751 #endif // wxUSE_STREAMS
753 // give GTK+ a chance to call GTK_EndProcessDetector here and
754 // also repaint the GUI
758 int exitcode
= data
->exitcode
;
764 else // async execution
766 // async execution, nothing special to do - caller will be
767 // notified about the process termination if process != NULL, data
768 // will be deleted in GTK_EndProcessDetector
769 data
->process
= process
;
771 data
->tag
= wxAddProcessCallback(data
, end_proc_detect
[0]);
773 close(end_proc_detect
[1]); // close writing side
778 wxASSERT_MSG( sync
, wxT("async execution not supported yet") );
781 if ( waitpid(pid
, &exitcode
, 0) == -1 || !WIFEXITED(exitcode
) )
783 wxLogSysError(_("Waiting for subprocess termination failed"));
791 #undef ERROR_RETURN_CODE
794 // ----------------------------------------------------------------------------
795 // file and directory functions
796 // ----------------------------------------------------------------------------
798 const wxChar
* wxGetHomeDir( wxString
*home
)
800 *home
= wxGetUserHome( wxString() );
802 if ( home
->IsEmpty() )
806 if ( tmp
.Last() != wxT(']'))
807 if ( tmp
.Last() != wxT('/')) *home
<< wxT('/');
809 return home
->c_str();
813 const wxMB2WXbuf
wxGetUserHome( const wxString
&user
)
814 #else // just for binary compatibility -- there is no 'const' here
815 char *wxGetUserHome( const wxString
&user
)
818 struct passwd
*who
= (struct passwd
*) NULL
;
824 if ((ptr
= wxGetenv(wxT("HOME"))) != NULL
)
828 if ((ptr
= wxGetenv(wxT("USER"))) != NULL
|| (ptr
= wxGetenv(wxT("LOGNAME"))) != NULL
)
830 who
= getpwnam(wxConvertWX2MB(ptr
));
833 // We now make sure the the user exists!
836 who
= getpwuid(getuid());
841 who
= getpwnam (user
.mb_str());
844 return wxConvertMB2WX(who
? who
->pw_dir
: 0);
847 // ----------------------------------------------------------------------------
848 // network and user id routines
849 // ----------------------------------------------------------------------------
851 // retrieve either the hostname or FQDN depending on platform (caller must
852 // check whether it's one or the other, this is why this function is for
854 static bool wxGetHostNameInternal(wxChar
*buf
, int sz
)
856 wxCHECK_MSG( buf
, FALSE
, wxT("NULL pointer in wxGetHostNameInternal") );
860 // we're using uname() which is POSIX instead of less standard sysinfo()
861 #if defined(HAVE_UNAME)
863 bool ok
= uname(&uts
) != -1;
866 wxStrncpy(buf
, wxConvertMB2WX(uts
.nodename
), sz
- 1);
869 #elif defined(HAVE_GETHOSTNAME)
870 bool ok
= gethostname(buf
, sz
) != -1;
871 #else // no uname, no gethostname
872 wxFAIL_MSG(wxT("don't know host name for this machine"));
875 #endif // uname/gethostname
879 wxLogSysError(_("Cannot get the hostname"));
885 bool wxGetHostName(wxChar
*buf
, int sz
)
887 bool ok
= wxGetHostNameInternal(buf
, sz
);
891 // BSD systems return the FQDN, we only want the hostname, so extract
892 // it (we consider that dots are domain separators)
893 wxChar
*dot
= wxStrchr(buf
, wxT('.'));
904 bool wxGetFullHostName(wxChar
*buf
, int sz
)
906 bool ok
= wxGetHostNameInternal(buf
, sz
);
910 if ( !wxStrchr(buf
, wxT('.')) )
912 struct hostent
*host
= gethostbyname(wxConvertWX2MB(buf
));
915 wxLogSysError(_("Cannot get the official hostname"));
921 // the canonical name
922 wxStrncpy(buf
, wxConvertMB2WX(host
->h_name
), sz
);
925 //else: it's already a FQDN (BSD behaves this way)
931 bool wxGetUserId(wxChar
*buf
, int sz
)
936 if ((who
= getpwuid(getuid ())) != NULL
)
938 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz
- 1);
945 bool wxGetUserName(wxChar
*buf
, int sz
)
950 if ((who
= getpwuid (getuid ())) != NULL
)
952 // pw_gecos field in struct passwd is not standard
954 char *comma
= strchr(who
->pw_gecos
, ',');
956 *comma
= '\0'; // cut off non-name comment fields
957 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_gecos
), sz
- 1);
958 #else // !HAVE_PW_GECOS
959 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz
- 1);
960 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
967 wxString
wxGetOsDescription()
969 #ifndef WXWIN_OS_DESCRIPTION
970 #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
972 return WXWIN_OS_DESCRIPTION
;
976 // this function returns the GUI toolkit version in GUI programs, but OS
977 // version in non-GUI ones
980 int wxGetOsVersion(int *majorVsn
, int *minorVsn
)
985 if ( sscanf(WXWIN_OS_DESCRIPTION
, "%s %d.%d", name
, &major
, &minor
) != 3 )
987 // unreckognized uname string format
1001 long wxGetFreeMemory()
1003 #if defined(__LINUX__)
1004 // get it from /proc/meminfo
1005 FILE *fp
= fopen("/proc/meminfo", "r");
1011 if ( fgets(buf
, WXSIZEOF(buf
), fp
) && fgets(buf
, WXSIZEOF(buf
), fp
) )
1013 long memTotal
, memUsed
;
1014 sscanf(buf
, "Mem: %ld %ld %ld", &memTotal
, &memUsed
, &memFree
);
1021 #elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES)
1022 return sysconf(_SC_AVPHYS_PAGES
)*sysconf(_SC_PAGESIZE
);
1023 //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1026 // can't find it out
1030 bool wxGetDiskSpace(const wxString
& path
, wxLongLong
*pTotal
, wxLongLong
*pFree
)
1035 if ( statfs(path
, &fs
) != 0 )
1037 wxLogSysError("Failed to get file system statistics");
1044 *pTotal
= wxLongLong(fs
.f_blocks
) * fs
.f_bsize
;
1049 *pFree
= wxLongLong(fs
.f_bavail
) * fs
.f_bsize
;
1053 #endif // HAVE_STATFS
1058 // ----------------------------------------------------------------------------
1060 // ----------------------------------------------------------------------------
1062 bool wxGetEnv(const wxString
& var
, wxString
*value
)
1064 // wxGetenv is defined as getenv()
1065 wxChar
*p
= wxGetenv(var
);
1077 bool wxSetEnv(const wxString
& variable
, const wxChar
*value
)
1079 #if defined(HAVE_SETENV)
1080 return setenv(variable
.mb_str(), value
? wxString(value
).mb_str().data()
1081 : NULL
, 1 /* overwrite */) == 0;
1082 #elif defined(HAVE_PUTENV)
1083 wxString s
= variable
;
1085 s
<< _T('=') << value
;
1087 // transform to ANSI
1088 const char *p
= s
.mb_str();
1090 // the string will be free()d by libc
1091 char *buf
= (char *)malloc(strlen(p
) + 1);
1094 return putenv(buf
) == 0;
1095 #else // no way to set an env var
1100 // ----------------------------------------------------------------------------
1102 // ----------------------------------------------------------------------------
1104 #if wxUSE_ON_FATAL_EXCEPTION
1108 static void wxFatalSignalHandler(wxTYPE_SA_HANDLER
)
1112 // give the user a chance to do something special about this
1113 wxTheApp
->OnFatalException();
1119 bool wxHandleFatalExceptions(bool doit
)
1122 static bool s_savedHandlers
= FALSE
;
1123 static struct sigaction s_handlerFPE
,
1129 if ( doit
&& !s_savedHandlers
)
1131 // install the signal handler
1132 struct sigaction act
;
1134 // some systems extend it with non std fields, so zero everything
1135 memset(&act
, 0, sizeof(act
));
1137 act
.sa_handler
= wxFatalSignalHandler
;
1138 sigemptyset(&act
.sa_mask
);
1141 ok
&= sigaction(SIGFPE
, &act
, &s_handlerFPE
) == 0;
1142 ok
&= sigaction(SIGILL
, &act
, &s_handlerILL
) == 0;
1143 ok
&= sigaction(SIGBUS
, &act
, &s_handlerBUS
) == 0;
1144 ok
&= sigaction(SIGSEGV
, &act
, &s_handlerSEGV
) == 0;
1147 wxLogDebug(_T("Failed to install our signal handler."));
1150 s_savedHandlers
= TRUE
;
1152 else if ( s_savedHandlers
)
1154 // uninstall the signal handler
1155 ok
&= sigaction(SIGFPE
, &s_handlerFPE
, NULL
) == 0;
1156 ok
&= sigaction(SIGILL
, &s_handlerILL
, NULL
) == 0;
1157 ok
&= sigaction(SIGBUS
, &s_handlerBUS
, NULL
) == 0;
1158 ok
&= sigaction(SIGSEGV
, &s_handlerSEGV
, NULL
) == 0;
1161 wxLogDebug(_T("Failed to uninstall our signal handler."));
1164 s_savedHandlers
= FALSE
;
1166 //else: nothing to do
1171 #endif // wxUSE_ON_FATAL_EXCEPTION
1173 // ----------------------------------------------------------------------------
1174 // error and debug output routines (deprecated, use wxLog)
1175 // ----------------------------------------------------------------------------
1177 void wxDebugMsg( const char *format
, ... )
1180 va_start( ap
, format
);
1181 vfprintf( stderr
, format
, ap
);
1186 void wxError( const wxString
&msg
, const wxString
&title
)
1188 wxFprintf( stderr
, _("Error ") );
1189 if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) );
1190 if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) );
1191 wxFprintf( stderr
, wxT(".\n") );
1194 void wxFatalError( const wxString
&msg
, const wxString
&title
)
1196 wxFprintf( stderr
, _("Error ") );
1197 if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) );
1198 if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) );
1199 wxFprintf( stderr
, wxT(".\n") );
1200 exit(3); // the same exit code as for abort()