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 // notify user about termination if required
292 if ( proc_data
->process
)
294 proc_data
->process
->OnTerminate(proc_data
->pid
, proc_data
->exitcode
);
298 if ( proc_data
->pid
> 0 )
304 // let wxExecute() know that the process has terminated
311 // ----------------------------------------------------------------------------
312 // wxStream classes to support IO redirection in wxExecute
313 // ----------------------------------------------------------------------------
317 class wxProcessFileInputStream
: public wxInputStream
320 wxProcessFileInputStream(int fd
) { m_fd
= fd
; }
321 ~wxProcessFileInputStream() { close(m_fd
); }
323 virtual bool Eof() const;
326 size_t OnSysRead(void *buffer
, size_t bufsize
);
332 class wxProcessFileOutputStream
: public wxOutputStream
335 wxProcessFileOutputStream(int fd
) { m_fd
= fd
; }
336 ~wxProcessFileOutputStream() { close(m_fd
); }
339 size_t OnSysWrite(const void *buffer
, size_t bufsize
);
345 bool wxProcessFileInputStream::Eof() const
347 if ( m_lasterror
== wxSTREAM_EOF
)
350 // check if there is any input available
357 FD_SET(m_fd
, &readfds
);
358 switch ( select(m_fd
+ 1, &readfds
, NULL
, NULL
, &tv
) )
361 wxLogSysError(_("Impossible to get child process input"));
368 wxFAIL_MSG(_T("unexpected select() return value"));
369 // still fall through
372 // input available: check if there is any
373 return wxInputStream::Eof();
377 size_t wxProcessFileInputStream::OnSysRead(void *buffer
, size_t bufsize
)
379 int ret
= read(m_fd
, buffer
, bufsize
);
382 m_lasterror
= wxSTREAM_EOF
;
384 else if ( ret
== -1 )
386 m_lasterror
= wxSTREAM_READ_ERROR
;
391 m_lasterror
= wxSTREAM_NOERROR
;
397 size_t wxProcessFileOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
399 int ret
= write(m_fd
, buffer
, bufsize
);
402 m_lasterror
= wxSTREAM_WRITE_ERROR
;
407 m_lasterror
= wxSTREAM_NOERROR
;
413 // ----------------------------------------------------------------------------
414 // wxStreamTempBuffer
415 // ----------------------------------------------------------------------------
418 Extract of a mail to wx-users to give the context of the problem we are
419 trying to solve here:
421 MC> If I run the command:
422 MC> find . -name "*.h" -exec grep linux {} \;
423 MC> in the exec sample synchronously from the 'Capture command output'
424 MC> menu, wxExecute never returns. I have to xkill it. Has anyone
425 MC> else encountered this?
427 Yes, I can reproduce it too.
429 I even think I understand why it happens: before launching the external
430 command we set up a pipe with a valid file descriptor on the reading side
431 when the output is redirected. So the subprocess happily writes to it ...
432 until the pipe buffer (which is usually quite big on Unix, I think the
433 default is 4Mb) is full. Then the writing process stops and waits until we
434 read some data from the pipe to be able to continue writing to it but we
435 never do it because we wait until it terminates to start reading and so we
436 have a classical deadlock.
438 Here is the fix: we now read the output as soon as it appears into a temp
439 buffer (wxStreamTempBuffer object) and later just stuff it back into the
440 stream when the process terminates. See supporting code in wxExecute()
444 class wxStreamTempBuffer
447 wxStreamTempBuffer();
449 // call to associate a stream with this buffer, otherwise nothing happens
451 void Init(wxInputStream
*stream
);
453 // check for input on our stream and cache it in our buffer if any
456 ~wxStreamTempBuffer();
459 // the stream we're buffering, if NULL we don't do anything at all
460 wxInputStream
*m_stream
;
462 // the buffer of size m_size (NULL if m_size == 0)
465 // the size of the buffer
469 wxStreamTempBuffer::wxStreamTempBuffer()
476 void wxStreamTempBuffer::Init(wxInputStream
*stream
)
481 void wxStreamTempBuffer::Update()
483 if ( m_stream
&& !m_stream
->Eof() )
485 // realloc in blocks of 1Kb - surely not the best strategy but which
487 static const size_t incSize
= 1024;
489 void *buf
= realloc(m_buffer
, m_size
+ incSize
);
492 // don't read any more, we don't have enough memory to do it
495 else // got memory for the buffer
498 m_stream
->Read((char *)m_buffer
+ m_size
, incSize
);
504 wxStreamTempBuffer::~wxStreamTempBuffer()
508 m_stream
->Ungetch(m_buffer
, m_size
);
513 #endif // wxUSE_STREAMS
515 long wxExecute(wxChar
**argv
,
519 // for the sync execution, we return -1 to indicate failure, but for async
520 // case we return 0 which is never a valid PID
522 // we define this as a macro, not a variable, to avoid compiler warnings
523 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
524 #define ERROR_RETURN_CODE ((sync) ? -1 : 0)
526 wxCHECK_MSG( *argv
, ERROR_RETURN_CODE
, wxT("can't exec empty command") );
530 char *mb_argv
[WXEXECUTE_NARGS
];
532 while (argv
[mb_argc
])
534 wxWX2MBbuf mb_arg
= wxConvertWX2MB(argv
[mb_argc
]);
535 mb_argv
[mb_argc
] = strdup(mb_arg
);
538 mb_argv
[mb_argc
] = (char *) NULL
;
540 // this macro will free memory we used above
541 #define ARGS_CLEANUP \
542 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
543 free(mb_argv[mb_argc])
545 // no need for cleanup
548 wxChar
**mb_argv
= argv
;
549 #endif // Unicode/ANSI
553 int end_proc_detect
[2];
554 if ( pipe(end_proc_detect
) == -1 )
556 wxLogSysError( _("Pipe creation failed") );
557 wxLogError( _("Failed to execute '%s'\n"), *argv
);
561 return ERROR_RETURN_CODE
;
565 // pipes for inter process communication
566 int pipeIn
[2], // stdin
567 pipeOut
[2], // stdout
568 pipeErr
[2]; // stderr
570 pipeIn
[0] = pipeIn
[1] =
571 pipeOut
[0] = pipeOut
[1] =
572 pipeErr
[0] = pipeErr
[1] = -1;
574 if ( process
&& process
->IsRedirected() )
576 if ( pipe(pipeIn
) == -1 || pipe(pipeOut
) == -1 || pipe(pipeErr
) == -1 )
579 // free previously allocated resources
580 close(end_proc_detect
[0]);
581 close(end_proc_detect
[1]);
584 wxLogSysError( _("Pipe creation failed") );
585 wxLogError( _("Failed to execute '%s'\n"), *argv
);
589 return ERROR_RETURN_CODE
;
600 if ( pid
== -1 ) // error?
603 close(end_proc_detect
[0]);
604 close(end_proc_detect
[1]);
613 wxLogSysError( _("Fork failed") );
617 return ERROR_RETURN_CODE
;
619 else if ( pid
== 0 ) // we're in child
622 close(end_proc_detect
[0]); // close reading side
625 // These lines close the open file descriptors to to avoid any
626 // input/output which might block the process or irritate the user. If
627 // one wants proper IO for the subprocess, the right thing to do is to
628 // start an xterm executing it.
631 for ( int fd
= 0; fd
< FD_SETSIZE
; fd
++ )
633 if ( fd
== pipeIn
[0] || fd
== pipeOut
[1] || fd
== pipeErr
[1]
635 || fd
== end_proc_detect
[1]
639 // don't close this one, we still need it
643 // leave stderr opened too, it won't do any hurm
644 if ( fd
!= STDERR_FILENO
)
649 // redirect stdio, stdout and stderr
650 if ( pipeIn
[0] != -1 )
652 if ( dup2(pipeIn
[0], STDIN_FILENO
) == -1 ||
653 dup2(pipeOut
[1], STDOUT_FILENO
) == -1 ||
654 dup2(pipeErr
[1], STDERR_FILENO
) == -1 )
656 wxLogSysError(_("Failed to redirect child process input/output"));
664 execvp (*mb_argv
, mb_argv
);
666 // there is no return after successful exec()
669 // some compilers complain about missing return - of course, they
670 // should know that exit() doesn't return but what else can we do if
672 #if defined(__VMS) || defined(__INTEL_COMPILER)
676 else // we're in parent
680 // pipe initialization: construction of the wxStreams
682 wxStreamTempBuffer bufIn
, bufErr
;
683 #endif // wxUSE_STREAMS
685 if ( process
&& process
->IsRedirected() )
688 // in/out for subprocess correspond to our out/in
689 wxOutputStream
*outStream
= new wxProcessFileOutputStream(pipeIn
[1]);
690 wxInputStream
*inStream
= new wxProcessFileInputStream(pipeOut
[0]);
691 wxInputStream
*errStream
= new wxProcessFileInputStream(pipeErr
[0]);
693 process
->SetPipeStreams(inStream
, outStream
, errStream
);
695 bufIn
.Init(inStream
);
696 bufErr
.Init(inStream
);
697 #endif // wxUSE_STREAMS
699 close(pipeIn
[0]); // close reading side
700 close(pipeOut
[1]); // close writing side
701 close(pipeErr
[1]); // close writing side
704 #if wxUSE_GUI && !defined(__WXMICROWIN__)
705 wxEndProcessData
*data
= new wxEndProcessData
;
709 // we may have process for capturing the program output, but it's
710 // not used in wxEndProcessData in the case of sync execution
711 data
->process
= NULL
;
713 // sync execution: indicate it by negating the pid
715 data
->tag
= wxAddProcessCallback(data
, end_proc_detect
[0]);
717 close(end_proc_detect
[1]); // close writing side
722 // data->pid will be set to 0 from GTK_EndProcessDetector when the
723 // process terminates
724 while ( data
->pid
!= 0 )
729 #endif // wxUSE_STREAMS
731 // give GTK+ a chance to call GTK_EndProcessDetector here and
732 // also repaint the GUI
736 int exitcode
= data
->exitcode
;
742 else // async execution
744 // async execution, nothing special to do - caller will be
745 // notified about the process termination if process != NULL, data
746 // will be deleted in GTK_EndProcessDetector
747 data
->process
= process
;
749 data
->tag
= wxAddProcessCallback(data
, end_proc_detect
[0]);
751 close(end_proc_detect
[1]); // close writing side
756 wxASSERT_MSG( sync
, wxT("async execution not supported yet") );
759 if ( waitpid(pid
, &exitcode
, 0) == -1 || !WIFEXITED(exitcode
) )
761 wxLogSysError(_("Waiting for subprocess termination failed"));
769 #undef ERROR_RETURN_CODE
772 // ----------------------------------------------------------------------------
773 // file and directory functions
774 // ----------------------------------------------------------------------------
776 const wxChar
* wxGetHomeDir( wxString
*home
)
778 *home
= wxGetUserHome( wxString() );
780 if ( home
->IsEmpty() )
784 if ( tmp
.Last() != wxT(']'))
785 if ( tmp
.Last() != wxT('/')) *home
<< wxT('/');
787 return home
->c_str();
791 const wxMB2WXbuf
wxGetUserHome( const wxString
&user
)
792 #else // just for binary compatibility -- there is no 'const' here
793 char *wxGetUserHome( const wxString
&user
)
796 struct passwd
*who
= (struct passwd
*) NULL
;
802 if ((ptr
= wxGetenv(wxT("HOME"))) != NULL
)
806 if ((ptr
= wxGetenv(wxT("USER"))) != NULL
|| (ptr
= wxGetenv(wxT("LOGNAME"))) != NULL
)
808 who
= getpwnam(wxConvertWX2MB(ptr
));
811 // We now make sure the the user exists!
814 who
= getpwuid(getuid());
819 who
= getpwnam (user
.mb_str());
822 return wxConvertMB2WX(who
? who
->pw_dir
: 0);
825 // ----------------------------------------------------------------------------
826 // network and user id routines
827 // ----------------------------------------------------------------------------
829 // retrieve either the hostname or FQDN depending on platform (caller must
830 // check whether it's one or the other, this is why this function is for
832 static bool wxGetHostNameInternal(wxChar
*buf
, int sz
)
834 wxCHECK_MSG( buf
, FALSE
, wxT("NULL pointer in wxGetHostNameInternal") );
838 // we're using uname() which is POSIX instead of less standard sysinfo()
839 #if defined(HAVE_UNAME)
841 bool ok
= uname(&uts
) != -1;
844 wxStrncpy(buf
, wxConvertMB2WX(uts
.nodename
), sz
- 1);
847 #elif defined(HAVE_GETHOSTNAME)
848 bool ok
= gethostname(buf
, sz
) != -1;
849 #else // no uname, no gethostname
850 wxFAIL_MSG(wxT("don't know host name for this machine"));
853 #endif // uname/gethostname
857 wxLogSysError(_("Cannot get the hostname"));
863 bool wxGetHostName(wxChar
*buf
, int sz
)
865 bool ok
= wxGetHostNameInternal(buf
, sz
);
869 // BSD systems return the FQDN, we only want the hostname, so extract
870 // it (we consider that dots are domain separators)
871 wxChar
*dot
= wxStrchr(buf
, wxT('.'));
882 bool wxGetFullHostName(wxChar
*buf
, int sz
)
884 bool ok
= wxGetHostNameInternal(buf
, sz
);
888 if ( !wxStrchr(buf
, wxT('.')) )
890 struct hostent
*host
= gethostbyname(wxConvertWX2MB(buf
));
893 wxLogSysError(_("Cannot get the official hostname"));
899 // the canonical name
900 wxStrncpy(buf
, wxConvertMB2WX(host
->h_name
), sz
);
903 //else: it's already a FQDN (BSD behaves this way)
909 bool wxGetUserId(wxChar
*buf
, int sz
)
914 if ((who
= getpwuid(getuid ())) != NULL
)
916 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz
- 1);
923 bool wxGetUserName(wxChar
*buf
, int sz
)
928 if ((who
= getpwuid (getuid ())) != NULL
)
930 // pw_gecos field in struct passwd is not standard
932 char *comma
= strchr(who
->pw_gecos
, ',');
934 *comma
= '\0'; // cut off non-name comment fields
935 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_gecos
), sz
- 1);
936 #else // !HAVE_PW_GECOS
937 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz
- 1);
938 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
945 wxString
wxGetOsDescription()
947 #ifndef WXWIN_OS_DESCRIPTION
948 #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
950 return WXWIN_OS_DESCRIPTION
;
954 // this function returns the GUI toolkit version in GUI programs, but OS
955 // version in non-GUI ones
958 int wxGetOsVersion(int *majorVsn
, int *minorVsn
)
963 if ( sscanf(WXWIN_OS_DESCRIPTION
, "%s %d.%d", name
, &major
, &minor
) != 3 )
965 // unreckognized uname string format
979 long wxGetFreeMemory()
981 #if defined(__LINUX__)
982 // get it from /proc/meminfo
983 FILE *fp
= fopen("/proc/meminfo", "r");
989 if ( fgets(buf
, WXSIZEOF(buf
), fp
) && fgets(buf
, WXSIZEOF(buf
), fp
) )
991 long memTotal
, memUsed
;
992 sscanf(buf
, "Mem: %ld %ld %ld", &memTotal
, &memUsed
, &memFree
);
999 #elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES)
1000 return sysconf(_SC_AVPHYS_PAGES
)*sysconf(_SC_PAGESIZE
);
1001 //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1004 // can't find it out
1008 bool wxGetDiskSpace(const wxString
& path
, wxLongLong
*pTotal
, wxLongLong
*pFree
)
1013 if ( statfs(path
, &fs
) != 0 )
1015 wxLogSysError("Failed to get file system statistics");
1022 *pTotal
= wxLongLong(fs
.f_blocks
) * fs
.f_bsize
;
1027 *pFree
= wxLongLong(fs
.f_bavail
) * fs
.f_bsize
;
1031 #endif // HAVE_STATFS
1036 // ----------------------------------------------------------------------------
1038 // ----------------------------------------------------------------------------
1040 bool wxGetEnv(const wxString
& var
, wxString
*value
)
1042 // wxGetenv is defined as getenv()
1043 wxChar
*p
= wxGetenv(var
);
1055 bool wxSetEnv(const wxString
& variable
, const wxChar
*value
)
1057 #if defined(HAVE_SETENV)
1058 return setenv(variable
.mb_str(), value
? wxString(value
).mb_str().data()
1059 : NULL
, 1 /* overwrite */) == 0;
1060 #elif defined(HAVE_PUTENV)
1061 wxString s
= variable
;
1063 s
<< _T('=') << value
;
1065 // transform to ANSI
1066 const char *p
= s
.mb_str();
1068 // the string will be free()d by libc
1069 char *buf
= (char *)malloc(strlen(p
) + 1);
1072 return putenv(buf
) == 0;
1073 #else // no way to set an env var
1078 // ----------------------------------------------------------------------------
1080 // ----------------------------------------------------------------------------
1082 #if wxUSE_ON_FATAL_EXCEPTION
1086 static void wxFatalSignalHandler(wxTYPE_SA_HANDLER
)
1090 // give the user a chance to do something special about this
1091 wxTheApp
->OnFatalException();
1097 bool wxHandleFatalExceptions(bool doit
)
1100 static bool s_savedHandlers
= FALSE
;
1101 static struct sigaction s_handlerFPE
,
1107 if ( doit
&& !s_savedHandlers
)
1109 // install the signal handler
1110 struct sigaction act
;
1112 // some systems extend it with non std fields, so zero everything
1113 memset(&act
, 0, sizeof(act
));
1115 act
.sa_handler
= wxFatalSignalHandler
;
1116 sigemptyset(&act
.sa_mask
);
1119 ok
&= sigaction(SIGFPE
, &act
, &s_handlerFPE
) == 0;
1120 ok
&= sigaction(SIGILL
, &act
, &s_handlerILL
) == 0;
1121 ok
&= sigaction(SIGBUS
, &act
, &s_handlerBUS
) == 0;
1122 ok
&= sigaction(SIGSEGV
, &act
, &s_handlerSEGV
) == 0;
1125 wxLogDebug(_T("Failed to install our signal handler."));
1128 s_savedHandlers
= TRUE
;
1130 else if ( s_savedHandlers
)
1132 // uninstall the signal handler
1133 ok
&= sigaction(SIGFPE
, &s_handlerFPE
, NULL
) == 0;
1134 ok
&= sigaction(SIGILL
, &s_handlerILL
, NULL
) == 0;
1135 ok
&= sigaction(SIGBUS
, &s_handlerBUS
, NULL
) == 0;
1136 ok
&= sigaction(SIGSEGV
, &s_handlerSEGV
, NULL
) == 0;
1139 wxLogDebug(_T("Failed to uninstall our signal handler."));
1142 s_savedHandlers
= FALSE
;
1144 //else: nothing to do
1149 #endif // wxUSE_ON_FATAL_EXCEPTION
1151 // ----------------------------------------------------------------------------
1152 // error and debug output routines (deprecated, use wxLog)
1153 // ----------------------------------------------------------------------------
1155 void wxDebugMsg( const char *format
, ... )
1158 va_start( ap
, format
);
1159 vfprintf( stderr
, format
, ap
);
1164 void wxError( const wxString
&msg
, const wxString
&title
)
1166 wxFprintf( stderr
, _("Error ") );
1167 if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) );
1168 if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) );
1169 wxFprintf( stderr
, wxT(".\n") );
1172 void wxFatalError( const wxString
&msg
, const wxString
&title
)
1174 wxFprintf( stderr
, _("Error ") );
1175 if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) );
1176 if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) );
1177 wxFprintf( stderr
, wxT(".\n") );
1178 exit(3); // the same exit code as for abort()