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 <sys/statvfs.h>
43 #define statfs statvfs
44 #endif // HAVE_STATVFS
47 #include "wx/unix/execute.h"
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
60 #include <sys/types.h>
67 #include <fcntl.h> // for O_WRONLY and friends
68 #include <time.h> // nanosleep() and/or usleep()
69 #include <ctype.h> // isspace()
70 #include <sys/time.h> // needed for FD_SETSIZE
73 #include <sys/utsname.h> // for uname()
76 // ----------------------------------------------------------------------------
77 // conditional compilation
78 // ----------------------------------------------------------------------------
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.
83 #if !defined(HAVE_USLEEP) && \
84 (defined(__SUN__) && !defined(__SunOs_5_6) && \
85 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
86 defined(__osf__) || defined(__EMX__)
90 int usleep(unsigned int usec
);
93 /* I copied this from the XFree86 diffs. AV. */
94 #define INCL_DOSPROCESS
96 inline void usleep(unsigned long delay
)
98 DosSleep(delay
? (delay
/1000l) : 1l);
100 #else // !Sun && !EMX
101 void usleep(unsigned long usec
);
103 #endif // Sun/EMX/Something else
106 #define HAVE_USLEEP 1
107 #endif // Unices without usleep()
109 // ============================================================================
111 // ============================================================================
113 // ----------------------------------------------------------------------------
115 // ----------------------------------------------------------------------------
117 void wxSleep(int nSecs
)
122 void wxUsleep(unsigned long milliseconds
)
124 #if defined(HAVE_NANOSLEEP)
126 tmReq
.tv_sec
= (time_t)(milliseconds
/ 1000);
127 tmReq
.tv_nsec
= (milliseconds
% 1000) * 1000 * 1000;
129 // we're not interested in remaining time nor in return value
130 (void)nanosleep(&tmReq
, (timespec
*)NULL
);
131 #elif defined(HAVE_USLEEP)
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
136 #if defined(__SUN__) && wxUSE_THREADS
137 #error "usleep() cannot be used in MT programs under Solaris."
140 usleep(milliseconds
* 1000); // usleep(3) wants microseconds
141 #elif defined(HAVE_SLEEP)
142 // under BeOS sleep() takes seconds (what about other platforms, if any?)
143 sleep(milliseconds
* 1000);
144 #else // !sleep function
145 #error "usleep() or nanosleep() function required for wxUsleep"
146 #endif // sleep function
149 // ----------------------------------------------------------------------------
150 // process management
151 // ----------------------------------------------------------------------------
153 int wxKill(long pid
, wxSignal sig
, wxKillError
*rc
)
155 int err
= kill((pid_t
)pid
, (int)sig
);
165 *rc
= wxKILL_BAD_SIGNAL
;
169 *rc
= wxKILL_ACCESS_DENIED
;
173 *rc
= wxKILL_NO_PROCESS
;
177 // this goes against Unix98 docs so log it
178 wxLogDebug(_T("unexpected kill(2) return value %d"), err
);
188 #define WXEXECUTE_NARGS 127
190 long wxExecute( const wxString
& command
, int flags
, wxProcess
*process
)
192 wxCHECK_MSG( !command
.IsEmpty(), 0, wxT("can't exec empty command") );
195 wxChar
*argv
[WXEXECUTE_NARGS
];
197 const wxChar
*cptr
= command
.c_str();
198 wxChar quotechar
= wxT('\0'); // is arg quoted?
199 bool escaped
= FALSE
;
201 // split the command line in arguments
205 quotechar
= wxT('\0');
207 // eat leading whitespace:
208 while ( wxIsspace(*cptr
) )
211 if ( *cptr
== wxT('\'') || *cptr
== wxT('"') )
216 if ( *cptr
== wxT('\\') && ! escaped
)
223 // all other characters:
227 // have we reached the end of the argument?
228 if ( (*cptr
== quotechar
&& ! escaped
)
229 || (quotechar
== wxT('\0') && wxIsspace(*cptr
))
230 || *cptr
== wxT('\0') )
232 wxASSERT_MSG( argc
< WXEXECUTE_NARGS
,
233 wxT("too many arguments in wxExecute") );
235 argv
[argc
] = new wxChar
[argument
.length() + 1];
236 wxStrcpy(argv
[argc
], argument
.c_str());
239 // if not at end of buffer, swallow last character:
243 break; // done with this one, start over
249 // do execute the command
250 long lRc
= wxExecute(argv
, flags
, process
);
255 delete [] argv
[argc
++];
260 // ----------------------------------------------------------------------------
262 // ----------------------------------------------------------------------------
264 static wxString
wxMakeShellCommand(const wxString
& command
)
269 // just an interactive shell
274 // execute command in a shell
275 cmd
<< _T("/bin/sh -c '") << command
<< _T('\'');
281 bool wxShell(const wxString
& command
)
283 return wxExecute(wxMakeShellCommand(command
), wxEXEC_SYNC
) == 0;
286 bool wxShell(const wxString
& command
, wxArrayString
& output
)
288 wxCHECK_MSG( !!command
, FALSE
, _T("can't exec shell non interactively") );
290 return wxExecute(wxMakeShellCommand(command
), output
);
295 void wxHandleProcessTermination(wxEndProcessData
*proc_data
)
297 // notify user about termination if required
298 if ( proc_data
->process
)
300 proc_data
->process
->OnTerminate(proc_data
->pid
, proc_data
->exitcode
);
304 if ( proc_data
->pid
> 0 )
310 // let wxExecute() know that the process has terminated
317 // ----------------------------------------------------------------------------
318 // wxStream classes to support IO redirection in wxExecute
319 // ----------------------------------------------------------------------------
323 class wxProcessFileInputStream
: public wxInputStream
326 wxProcessFileInputStream(int fd
) { m_fd
= fd
; }
327 ~wxProcessFileInputStream() { close(m_fd
); }
329 virtual bool Eof() const;
332 size_t OnSysRead(void *buffer
, size_t bufsize
);
338 class wxProcessFileOutputStream
: public wxOutputStream
341 wxProcessFileOutputStream(int fd
) { m_fd
= fd
; }
342 ~wxProcessFileOutputStream() { close(m_fd
); }
345 size_t OnSysWrite(const void *buffer
, size_t bufsize
);
351 bool wxProcessFileInputStream::Eof() const
353 if ( m_lasterror
== wxSTREAM_EOF
)
356 // check if there is any input available
363 FD_SET(m_fd
, &readfds
);
364 switch ( select(m_fd
+ 1, &readfds
, NULL
, NULL
, &tv
) )
367 wxLogSysError(_("Impossible to get child process input"));
374 wxFAIL_MSG(_T("unexpected select() return value"));
375 // still fall through
378 // input available: check if there is any
379 return wxInputStream::Eof();
383 size_t wxProcessFileInputStream::OnSysRead(void *buffer
, size_t bufsize
)
385 int ret
= read(m_fd
, buffer
, bufsize
);
388 m_lasterror
= wxSTREAM_EOF
;
390 else if ( ret
== -1 )
392 m_lasterror
= wxSTREAM_READ_ERROR
;
397 m_lasterror
= wxSTREAM_NOERROR
;
403 size_t wxProcessFileOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
405 int ret
= write(m_fd
, buffer
, bufsize
);
408 m_lasterror
= wxSTREAM_WRITE_ERROR
;
413 m_lasterror
= wxSTREAM_NOERROR
;
419 // ----------------------------------------------------------------------------
420 // wxStreamTempBuffer
421 // ----------------------------------------------------------------------------
424 Extract of a mail to wx-users to give the context of the problem we are
425 trying to solve here:
427 MC> If I run the command:
428 MC> find . -name "*.h" -exec grep linux {} \;
429 MC> in the exec sample synchronously from the 'Capture command output'
430 MC> menu, wxExecute never returns. I have to xkill it. Has anyone
431 MC> else encountered this?
433 Yes, I can reproduce it too.
435 I even think I understand why it happens: before launching the external
436 command we set up a pipe with a valid file descriptor on the reading side
437 when the output is redirected. So the subprocess happily writes to it ...
438 until the pipe buffer (which is usually quite big on Unix, I think the
439 default is 4Mb) is full. Then the writing process stops and waits until we
440 read some data from the pipe to be able to continue writing to it but we
441 never do it because we wait until it terminates to start reading and so we
442 have a classical deadlock.
444 Here is the fix: we now read the output as soon as it appears into a temp
445 buffer (wxStreamTempBuffer object) and later just stuff it back into the
446 stream when the process terminates. See supporting code in wxExecute()
450 class wxStreamTempBuffer
453 wxStreamTempBuffer();
455 // call to associate a stream with this buffer, otherwise nothing happens
457 void Init(wxInputStream
*stream
);
459 // check for input on our stream and cache it in our buffer if any
462 ~wxStreamTempBuffer();
465 // the stream we're buffering, if NULL we don't do anything at all
466 wxInputStream
*m_stream
;
468 // the buffer of size m_size (NULL if m_size == 0)
471 // the size of the buffer
475 wxStreamTempBuffer::wxStreamTempBuffer()
482 void wxStreamTempBuffer::Init(wxInputStream
*stream
)
487 void wxStreamTempBuffer::Update()
489 if ( m_stream
&& !m_stream
->Eof() )
491 // realloc in blocks of 1Kb - surely not the best strategy but which
493 static const size_t incSize
= 1024;
495 void *buf
= realloc(m_buffer
, m_size
+ incSize
);
498 // don't read any more, we don't have enough memory to do it
501 else // got memory for the buffer
504 m_stream
->Read((char *)m_buffer
+ m_size
, incSize
);
510 wxStreamTempBuffer::~wxStreamTempBuffer()
514 m_stream
->Ungetch(m_buffer
, m_size
);
519 #endif // wxUSE_STREAMS
521 long wxExecute(wxChar
**argv
,
525 // for the sync execution, we return -1 to indicate failure, but for async
526 // case we return 0 which is never a valid PID
528 // we define this as a macro, not a variable, to avoid compiler warnings
529 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
530 #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)
532 wxCHECK_MSG( *argv
, ERROR_RETURN_CODE
, wxT("can't exec empty command") );
536 char *mb_argv
[WXEXECUTE_NARGS
];
538 while (argv
[mb_argc
])
540 wxWX2MBbuf mb_arg
= wxConvertWX2MB(argv
[mb_argc
]);
541 mb_argv
[mb_argc
] = strdup(mb_arg
);
544 mb_argv
[mb_argc
] = (char *) NULL
;
546 // this macro will free memory we used above
547 #define ARGS_CLEANUP \
548 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
549 free(mb_argv[mb_argc])
551 // no need for cleanup
554 wxChar
**mb_argv
= argv
;
555 #endif // Unicode/ANSI
559 int end_proc_detect
[2];
560 if ( pipe(end_proc_detect
) == -1 )
562 wxLogSysError( _("Pipe creation failed") );
563 wxLogError( _("Failed to execute '%s'\n"), *argv
);
567 return ERROR_RETURN_CODE
;
571 // pipes for inter process communication
572 int pipeIn
[2], // stdin
573 pipeOut
[2], // stdout
574 pipeErr
[2]; // stderr
576 pipeIn
[0] = pipeIn
[1] =
577 pipeOut
[0] = pipeOut
[1] =
578 pipeErr
[0] = pipeErr
[1] = -1;
580 if ( process
&& process
->IsRedirected() )
582 if ( pipe(pipeIn
) == -1 || pipe(pipeOut
) == -1 || pipe(pipeErr
) == -1 )
585 // free previously allocated resources
586 close(end_proc_detect
[0]);
587 close(end_proc_detect
[1]);
590 wxLogSysError( _("Pipe creation failed") );
591 wxLogError( _("Failed to execute '%s'\n"), *argv
);
595 return ERROR_RETURN_CODE
;
606 if ( pid
== -1 ) // error?
609 close(end_proc_detect
[0]);
610 close(end_proc_detect
[1]);
619 wxLogSysError( _("Fork failed") );
623 return ERROR_RETURN_CODE
;
625 else if ( pid
== 0 ) // we're in child
628 close(end_proc_detect
[0]); // close reading side
631 // These lines close the open file descriptors to to avoid any
632 // input/output which might block the process or irritate the user. If
633 // one wants proper IO for the subprocess, the right thing to do is to
634 // start an xterm executing it.
635 if ( !(flags
& wxEXEC_SYNC
) )
637 for ( int fd
= 0; fd
< FD_SETSIZE
; fd
++ )
639 if ( fd
== pipeIn
[0] || fd
== pipeOut
[1] || fd
== pipeErr
[1]
641 || fd
== end_proc_detect
[1]
645 // don't close this one, we still need it
649 // leave stderr opened too, it won't do any hurm
650 if ( fd
!= STDERR_FILENO
)
655 if ( flags
& wxEXEC_MAKE_GROUP_LEADER
)
657 // Set process group to child process' pid. Then killing -pid
658 // of the parent will kill the process and all of its children.
664 // redirect stdio, stdout and stderr
665 if ( pipeIn
[0] != -1 )
667 if ( dup2(pipeIn
[0], STDIN_FILENO
) == -1 ||
668 dup2(pipeOut
[1], STDOUT_FILENO
) == -1 ||
669 dup2(pipeErr
[1], STDERR_FILENO
) == -1 )
671 wxLogSysError(_("Failed to redirect child process input/output"));
679 execvp (*mb_argv
, mb_argv
);
681 // there is no return after successful exec()
684 // some compilers complain about missing return - of course, they
685 // should know that exit() doesn't return but what else can we do if
687 #if defined(__VMS) || defined(__INTEL_COMPILER)
691 else // we're in parent
695 // pipe initialization: construction of the wxStreams
697 wxStreamTempBuffer bufIn
, bufErr
;
698 #endif // wxUSE_STREAMS
700 if ( process
&& process
->IsRedirected() )
703 // in/out for subprocess correspond to our out/in
704 wxOutputStream
*outStream
= new wxProcessFileOutputStream(pipeIn
[1]);
705 wxInputStream
*inStream
= new wxProcessFileInputStream(pipeOut
[0]);
706 wxInputStream
*errStream
= new wxProcessFileInputStream(pipeErr
[0]);
708 process
->SetPipeStreams(inStream
, outStream
, errStream
);
710 bufIn
.Init(inStream
);
711 bufErr
.Init(inStream
);
712 #endif // wxUSE_STREAMS
714 close(pipeIn
[0]); // close reading side
715 close(pipeOut
[1]); // close writing side
716 close(pipeErr
[1]); // close writing side
719 #if wxUSE_GUI && !defined(__WXMICROWIN__)
720 wxEndProcessData
*data
= new wxEndProcessData
;
722 if ( flags
& wxEXEC_SYNC
)
724 // we may have process for capturing the program output, but it's
725 // not used in wxEndProcessData in the case of sync execution
726 data
->process
= NULL
;
728 // sync execution: indicate it by negating the pid
730 data
->tag
= wxAddProcessCallback(data
, end_proc_detect
[0]);
732 close(end_proc_detect
[1]); // close writing side
737 // data->pid will be set to 0 from GTK_EndProcessDetector when the
738 // process terminates
739 while ( data
->pid
!= 0 )
744 #endif // wxUSE_STREAMS
746 // give GTK+ a chance to call GTK_EndProcessDetector here and
747 // also repaint the GUI
751 int exitcode
= data
->exitcode
;
757 else // async execution
759 // async execution, nothing special to do - caller will be
760 // notified about the process termination if process != NULL, data
761 // will be deleted in GTK_EndProcessDetector
762 data
->process
= process
;
764 data
->tag
= wxAddProcessCallback(data
, end_proc_detect
[0]);
766 close(end_proc_detect
[1]); // close writing side
772 wxASSERT_MSG( flags
& wxEXEC_SYNC
,
773 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
963 wxString
wxGetOsDescription()
965 #ifndef WXWIN_OS_DESCRIPTION
966 #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
968 return WXWIN_OS_DESCRIPTION
;
973 // this function returns the GUI toolkit version in GUI programs, but OS
974 // version in non-GUI ones
977 int wxGetOsVersion(int *majorVsn
, int *minorVsn
)
982 if ( sscanf(WXWIN_OS_DESCRIPTION
, "%s %d.%d", name
, &major
, &minor
) != 3 )
984 // unreckognized uname string format
998 long wxGetFreeMemory()
1000 #if defined(__LINUX__)
1001 // get it from /proc/meminfo
1002 FILE *fp
= fopen("/proc/meminfo", "r");
1008 if ( fgets(buf
, WXSIZEOF(buf
), fp
) && fgets(buf
, WXSIZEOF(buf
), fp
) )
1010 long memTotal
, memUsed
;
1011 sscanf(buf
, "Mem: %ld %ld %ld", &memTotal
, &memUsed
, &memFree
);
1018 #elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES)
1019 return sysconf(_SC_AVPHYS_PAGES
)*sysconf(_SC_PAGESIZE
);
1020 //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1023 // can't find it out
1027 bool wxGetDiskSpace(const wxString
& path
, wxLongLong
*pTotal
, wxLongLong
*pFree
)
1029 #if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
1030 // the case to "char *" is needed for AIX 4.3
1032 if ( statfs((char *)path
.fn_str(), &fs
) != 0 )
1034 wxLogSysError("Failed to get file system statistics");
1039 // under Solaris we might have to use fs.f_frsize instead as I think it
1040 // may be a multiple of the block size in general (TODO)
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(),
1081 value
? (const char *)wxString(value
).mb_str()
1083 1 /* overwrite */) == 0;
1084 #elif defined(HAVE_PUTENV)
1085 wxString s
= variable
;
1087 s
<< _T('=') << value
;
1089 // transform to ANSI
1090 const char *p
= s
.mb_str();
1092 // the string will be free()d by libc
1093 char *buf
= (char *)malloc(strlen(p
) + 1);
1096 return putenv(buf
) == 0;
1097 #else // no way to set an env var
1102 // ----------------------------------------------------------------------------
1104 // ----------------------------------------------------------------------------
1106 #if wxUSE_ON_FATAL_EXCEPTION
1110 extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER
)
1114 // give the user a chance to do something special about this
1115 wxTheApp
->OnFatalException();
1121 bool wxHandleFatalExceptions(bool doit
)
1124 static bool s_savedHandlers
= FALSE
;
1125 static struct sigaction s_handlerFPE
,
1131 if ( doit
&& !s_savedHandlers
)
1133 // install the signal handler
1134 struct sigaction act
;
1136 // some systems extend it with non std fields, so zero everything
1137 memset(&act
, 0, sizeof(act
));
1139 act
.sa_handler
= wxFatalSignalHandler
;
1140 sigemptyset(&act
.sa_mask
);
1143 ok
&= sigaction(SIGFPE
, &act
, &s_handlerFPE
) == 0;
1144 ok
&= sigaction(SIGILL
, &act
, &s_handlerILL
) == 0;
1145 ok
&= sigaction(SIGBUS
, &act
, &s_handlerBUS
) == 0;
1146 ok
&= sigaction(SIGSEGV
, &act
, &s_handlerSEGV
) == 0;
1149 wxLogDebug(_T("Failed to install our signal handler."));
1152 s_savedHandlers
= TRUE
;
1154 else if ( s_savedHandlers
)
1156 // uninstall the signal handler
1157 ok
&= sigaction(SIGFPE
, &s_handlerFPE
, NULL
) == 0;
1158 ok
&= sigaction(SIGILL
, &s_handlerILL
, NULL
) == 0;
1159 ok
&= sigaction(SIGBUS
, &s_handlerBUS
, NULL
) == 0;
1160 ok
&= sigaction(SIGSEGV
, &s_handlerSEGV
, NULL
) == 0;
1163 wxLogDebug(_T("Failed to uninstall our signal handler."));
1166 s_savedHandlers
= FALSE
;
1168 //else: nothing to do
1173 #endif // wxUSE_ON_FATAL_EXCEPTION
1175 // ----------------------------------------------------------------------------
1176 // error and debug output routines (deprecated, use wxLog)
1177 // ----------------------------------------------------------------------------
1179 #if WXWIN_COMPATIBILITY_2_2
1181 void wxDebugMsg( const char *format
, ... )
1184 va_start( ap
, format
);
1185 vfprintf( stderr
, format
, ap
);
1190 void wxError( const wxString
&msg
, const wxString
&title
)
1192 wxFprintf( stderr
, _("Error ") );
1193 if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) );
1194 if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) );
1195 wxFprintf( stderr
, wxT(".\n") );
1198 void wxFatalError( const wxString
&msg
, const wxString
&title
)
1200 wxFprintf( stderr
, _("Error ") );
1201 if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) );
1202 if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) );
1203 wxFprintf( stderr
, wxT(".\n") );
1204 exit(3); // the same exit code as for abort()
1207 #endif // WXWIN_COMPATIBILITY_2_2