]> git.saurik.com Git - wxWidgets.git/blob - src/unix/utilsunx.cpp
Funny resize behaviour fix.
[wxWidgets.git] / src / unix / utilsunx.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: utilsunx.cpp
3 // Purpose: generic Unix implementation of many wx functions
4 // Author: Vadim Zeitlin
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // ============================================================================
11 // declarations
12 // ============================================================================
13
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17
18 #include "wx/defs.h"
19 #include "wx/string.h"
20
21 #include "wx/intl.h"
22 #include "wx/log.h"
23 #include "wx/app.h"
24
25 #include "wx/utils.h"
26 #include "wx/process.h"
27 #include "wx/thread.h"
28
29 #include "wx/stream.h"
30
31 #if wxUSE_GUI
32 #include "wx/unix/execute.h"
33 #endif
34
35 #include <stdarg.h>
36 #include <dirent.h>
37 #include <string.h>
38 #include <sys/stat.h>
39 #include <sys/types.h>
40 #include <unistd.h>
41 #include <sys/wait.h>
42 #include <pwd.h>
43 #include <errno.h>
44 #include <netdb.h>
45 #include <signal.h>
46 #include <fcntl.h> // for O_WRONLY and friends
47 #include <time.h> // nanosleep() and/or usleep()
48 #include <ctype.h> // isspace()
49 #include <sys/time.h> // needed for FD_SETSIZE
50
51 #ifdef HAVE_UNAME
52 #include <sys/utsname.h> // for uname()
53 #endif // HAVE_UNAME
54
55 // ----------------------------------------------------------------------------
56 // conditional compilation
57 // ----------------------------------------------------------------------------
58
59 // many versions of Unices have this function, but it is not defined in system
60 // headers - please add your system here if it is the case for your OS.
61 // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
62 #if !defined(HAVE_USLEEP) && \
63 (defined(__SUN__) && !defined(__SunOs_5_6) && \
64 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
65 defined(__osf__) || defined(__EMX__)
66 extern "C"
67 {
68 #ifdef __SUN__
69 int usleep(unsigned int usec);
70 #else // !Sun
71 #ifdef __EMX__
72 /* I copied this from the XFree86 diffs. AV. */
73 #define INCL_DOSPROCESS
74 #include <os2.h>
75 inline void usleep(unsigned long delay)
76 {
77 DosSleep(delay ? (delay/1000l) : 1l);
78 }
79 #else // !Sun && !EMX
80 void usleep(unsigned long usec);
81 #endif
82 #endif // Sun/EMX/Something else
83 };
84
85 #define HAVE_USLEEP 1
86 #endif // Unices without usleep()
87
88 // ============================================================================
89 // implementation
90 // ============================================================================
91
92 // ----------------------------------------------------------------------------
93 // sleeping
94 // ----------------------------------------------------------------------------
95
96 void wxSleep(int nSecs)
97 {
98 sleep(nSecs);
99 }
100
101 void wxUsleep(unsigned long milliseconds)
102 {
103 #if defined(HAVE_NANOSLEEP)
104 timespec tmReq;
105 tmReq.tv_sec = (time_t)(milliseconds / 1000);
106 tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
107
108 // we're not interested in remaining time nor in return value
109 (void)nanosleep(&tmReq, (timespec *)NULL);
110 #elif defined(HAVE_USLEEP)
111 // uncomment this if you feel brave or if you are sure that your version
112 // of Solaris has a safe usleep() function but please notice that usleep()
113 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
114 // documented as MT-Safe
115 #if defined(__SUN__) && wxUSE_THREADS
116 #error "usleep() cannot be used in MT programs under Solaris."
117 #endif // Sun
118
119 usleep(milliseconds * 1000); // usleep(3) wants microseconds
120 #elif defined(HAVE_SLEEP)
121 // under BeOS sleep() takes seconds (what about other platforms, if any?)
122 sleep(milliseconds * 1000);
123 #else // !sleep function
124 #error "usleep() or nanosleep() function required for wxUsleep"
125 #endif // sleep function
126 }
127
128 // ----------------------------------------------------------------------------
129 // process management
130 // ----------------------------------------------------------------------------
131
132 int wxKill(long pid, wxSignal sig)
133 {
134 return kill((pid_t)pid, (int)sig);
135 }
136
137 #define WXEXECUTE_NARGS 127
138
139 long wxExecute( const wxString& command, bool sync, wxProcess *process )
140 {
141 wxCHECK_MSG( !command.IsEmpty(), 0, wxT("can't exec empty command") );
142
143 int argc = 0;
144 wxChar *argv[WXEXECUTE_NARGS];
145 wxString argument;
146 const wxChar *cptr = command.c_str();
147 wxChar quotechar = wxT('\0'); // is arg quoted?
148 bool escaped = FALSE;
149
150 // split the command line in arguments
151 do
152 {
153 argument=wxT("");
154 quotechar = wxT('\0');
155
156 // eat leading whitespace:
157 while ( wxIsspace(*cptr) )
158 cptr++;
159
160 if ( *cptr == wxT('\'') || *cptr == wxT('"') )
161 quotechar = *cptr++;
162
163 do
164 {
165 if ( *cptr == wxT('\\') && ! escaped )
166 {
167 escaped = TRUE;
168 cptr++;
169 continue;
170 }
171
172 // all other characters:
173 argument += *cptr++;
174 escaped = FALSE;
175
176 // have we reached the end of the argument?
177 if ( (*cptr == quotechar && ! escaped)
178 || (quotechar == wxT('\0') && wxIsspace(*cptr))
179 || *cptr == wxT('\0') )
180 {
181 wxASSERT_MSG( argc < WXEXECUTE_NARGS,
182 wxT("too many arguments in wxExecute") );
183
184 argv[argc] = new wxChar[argument.length() + 1];
185 wxStrcpy(argv[argc], argument.c_str());
186 argc++;
187
188 // if not at end of buffer, swallow last character:
189 if(*cptr)
190 cptr++;
191
192 break; // done with this one, start over
193 }
194 } while(*cptr);
195 } while(*cptr);
196 argv[argc] = NULL;
197
198 // do execute the command
199 long lRc = wxExecute(argv, sync, process);
200
201 // clean up
202 argc = 0;
203 while( argv[argc] )
204 delete [] argv[argc++];
205
206 return lRc;
207 }
208
209 // ----------------------------------------------------------------------------
210 // wxShell
211 // ----------------------------------------------------------------------------
212
213 static wxString wxMakeShellCommand(const wxString& command)
214 {
215 wxString cmd;
216 if ( !command )
217 {
218 // just an interactive shell
219 cmd = _T("xterm");
220 }
221 else
222 {
223 // execute command in a shell
224 cmd << _T("/bin/sh -c '") << command << _T('\'');
225 }
226
227 return cmd;
228 }
229
230 bool wxShell(const wxString& command)
231 {
232 return wxExecute(wxMakeShellCommand(command), TRUE /* sync */) == 0;
233 }
234
235 bool wxShell(const wxString& command, wxArrayString& output)
236 {
237 wxCHECK_MSG( !!command, FALSE, _T("can't exec shell non interactively") );
238
239 return wxExecute(wxMakeShellCommand(command), output);
240 }
241
242 #if wxUSE_GUI
243
244 void wxHandleProcessTermination(wxEndProcessData *proc_data)
245 {
246 int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid);
247
248 // waitpid is POSIX so should be available everywhere, however on older
249 // systems wait() might be used instead in a loop (until the right pid
250 // terminates)
251 int status = 0;
252 int rc;
253
254 // wait for child termination and if waitpid() was interrupted, try again
255 do
256 {
257 rc = waitpid(pid, &status, 0);
258 }
259 while ( rc == -1 && errno == EINTR );
260
261
262 if( rc == -1 || ! (WIFEXITED(status) || WIFSIGNALED(status)) )
263 {
264 wxLogSysError(_("Waiting for subprocess termination failed"));
265 /* AFAIK, this can only happen if something went wrong within
266 wxGTK, i.e. due to a race condition or some serious bug.
267 After having fixed the order of statements in
268 GTK_EndProcessDetector(). (KB)
269 */
270 }
271 else
272 {
273 // notify user about termination if required
274 if (proc_data->process)
275 {
276 proc_data->process->OnTerminate(proc_data->pid,
277 WEXITSTATUS(status));
278 }
279 // clean up
280 if ( proc_data->pid > 0 )
281 {
282 delete proc_data;
283 }
284 else
285 {
286 // wxExecute() will know about it
287 proc_data->exitcode = status;
288
289 proc_data->pid = 0;
290 }
291 }
292 }
293
294 #endif // wxUSE_GUI
295
296 // ----------------------------------------------------------------------------
297 // wxStream classes to support IO redirection in wxExecute
298 // ----------------------------------------------------------------------------
299
300 class wxProcessFileInputStream : public wxInputStream
301 {
302 public:
303 wxProcessFileInputStream(int fd) { m_fd = fd; }
304 ~wxProcessFileInputStream() { close(m_fd); }
305
306 virtual bool Eof() const;
307
308 protected:
309 size_t OnSysRead(void *buffer, size_t bufsize);
310
311 protected:
312 int m_fd;
313 };
314
315 class wxProcessFileOutputStream : public wxOutputStream
316 {
317 public:
318 wxProcessFileOutputStream(int fd) { m_fd = fd; }
319 ~wxProcessFileOutputStream() { close(m_fd); }
320
321 protected:
322 size_t OnSysWrite(const void *buffer, size_t bufsize);
323
324 protected:
325 int m_fd;
326 };
327
328 bool wxProcessFileInputStream::Eof() const
329 {
330 if ( m_lasterror == wxSTREAM_EOF )
331 return TRUE;
332
333 // check if there is any input available
334 struct timeval tv;
335 tv.tv_sec = 0;
336 tv.tv_usec = 0;
337
338 fd_set readfds;
339 FD_ZERO(&readfds);
340 FD_SET(m_fd, &readfds);
341 switch ( select(m_fd + 1, &readfds, NULL, NULL, &tv) )
342 {
343 case -1:
344 wxLogSysError(_("Impossible to get child process input"));
345 // fall through
346
347 case 0:
348 return TRUE;
349
350 default:
351 wxFAIL_MSG(_T("unexpected select() return value"));
352 // still fall through
353
354 case 1:
355 // input available: check if there is any
356 return wxInputStream::Eof();
357 }
358 }
359
360 size_t wxProcessFileInputStream::OnSysRead(void *buffer, size_t bufsize)
361 {
362 int ret = read(m_fd, buffer, bufsize);
363 if ( ret == 0 )
364 {
365 m_lasterror = wxSTREAM_EOF;
366 }
367 else if ( ret == -1 )
368 {
369 m_lasterror = wxSTREAM_READ_ERROR;
370 ret = 0;
371 }
372 else
373 {
374 m_lasterror = wxSTREAM_NOERROR;
375 }
376
377 return ret;
378 }
379
380 size_t wxProcessFileOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
381 {
382 int ret = write(m_fd, buffer, bufsize);
383 if ( ret == -1 )
384 {
385 m_lasterror = wxSTREAM_WRITE_ERROR;
386 ret = 0;
387 }
388 else
389 {
390 m_lasterror = wxSTREAM_NOERROR;
391 }
392
393 return ret;
394 }
395
396 long wxExecute(wxChar **argv,
397 bool sync,
398 wxProcess *process)
399 {
400 wxCHECK_MSG( *argv, 0, wxT("can't exec empty command") );
401
402 #if wxUSE_UNICODE
403 int mb_argc = 0;
404 char *mb_argv[WXEXECUTE_NARGS];
405
406 while (argv[mb_argc])
407 {
408 wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
409 mb_argv[mb_argc] = strdup(mb_arg);
410 mb_argc++;
411 }
412 mb_argv[mb_argc] = (char *) NULL;
413
414 // this macro will free memory we used above
415 #define ARGS_CLEANUP \
416 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
417 free(mb_argv[mb_argc])
418 #else // ANSI
419 // no need for cleanup
420 #define ARGS_CLEANUP
421
422 wxChar **mb_argv = argv;
423 #endif // Unicode/ANSI
424
425 #if wxUSE_GUI
426 // create pipes
427 int end_proc_detect[2];
428 if ( pipe(end_proc_detect) == -1 )
429 {
430 wxLogSysError( _("Pipe creation failed") );
431 wxLogError( _("Failed to execute '%s'\n"), *argv );
432
433 ARGS_CLEANUP;
434
435 return 0;
436 }
437 #endif // wxUSE_GUI
438
439 int pipeIn[2];
440 int pipeOut[2];
441 pipeIn[0] = pipeIn[1] =
442 pipeOut[0] = pipeOut[1] = -1;
443
444 if ( process && process->IsRedirected() )
445 {
446 if ( pipe(pipeIn) == -1 || pipe(pipeOut) == -1 )
447 {
448 #if wxUSE_GUI
449 // free previously allocated resources
450 close(end_proc_detect[0]);
451 close(end_proc_detect[1]);
452 #endif // wxUSE_GUI
453
454 wxLogSysError( _("Pipe creation failed") );
455 wxLogError( _("Failed to execute '%s'\n"), *argv );
456
457 ARGS_CLEANUP;
458
459 return 0;
460 }
461 }
462
463 // fork the process
464 #ifdef HAVE_VFORK
465 pid_t pid = vfork();
466 #else
467 pid_t pid = fork();
468 #endif
469
470 if ( pid == -1 ) // error?
471 {
472 #if wxUSE_GUI
473 close(end_proc_detect[0]);
474 close(end_proc_detect[1]);
475 close(pipeIn[0]);
476 close(pipeIn[1]);
477 close(pipeOut[0]);
478 close(pipeOut[1]);
479 #endif // wxUSE_GUI
480
481 wxLogSysError( _("Fork failed") );
482
483 ARGS_CLEANUP;
484
485 return 0;
486 }
487 else if ( pid == 0 ) // we're in child
488 {
489 #if wxUSE_GUI
490 close(end_proc_detect[0]); // close reading side
491 #endif // wxUSE_GUI
492
493 // These lines close the open file descriptors to to avoid any
494 // input/output which might block the process or irritate the user. If
495 // one wants proper IO for the subprocess, the right thing to do is to
496 // start an xterm executing it.
497 if ( !sync )
498 {
499 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
500 {
501 if ( fd == pipeIn[0] || fd == pipeOut[1]
502 #if wxUSE_GUI
503 || fd == end_proc_detect[1]
504 #endif // wxUSE_GUI
505 )
506 {
507 // don't close this one, we still need it
508 continue;
509 }
510
511 // leave stderr opened too, it won't do any hurm
512 if ( fd != STDERR_FILENO )
513 close(fd);
514 }
515 }
516
517 // redirect stdio and stdout
518 // (TODO: what about stderr?)
519 if ( pipeIn[0] != -1 )
520 {
521 if ( dup2(pipeIn[0], STDIN_FILENO) == -1 ||
522 dup2(pipeOut[1], STDOUT_FILENO) == -1 )
523 {
524 wxLogSysError(_("Failed to redirect child process "
525 "input/output"));
526 }
527
528 close(pipeIn[0]);
529 close(pipeOut[1]);
530 }
531
532 execvp (*mb_argv, mb_argv);
533
534 // there is no return after successful exec()
535 _exit(-1);
536 }
537 else // we're in parent
538 {
539 ARGS_CLEANUP;
540
541 // pipe initialization: construction of the wxStreams
542 if ( process && process->IsRedirected() )
543 {
544 // These two streams are relative to this process.
545 wxOutputStream *outStream = new wxProcessFileOutputStream(pipeIn[1]);
546 wxInputStream *inStream = new wxProcessFileInputStream(pipeOut[0]);
547 close(pipeIn[0]); // close reading side
548 close(pipeOut[1]); // close writing side
549
550 process->SetPipeStreams(inStream, outStream);
551 }
552
553 #if wxUSE_GUI
554 wxEndProcessData *data = new wxEndProcessData;
555
556 if ( sync )
557 {
558 // we may have process for capturing the program output, but it's
559 // not used in wxEndProcessData in the case of sync execution
560 data->process = NULL;
561
562 // sync execution: indicate it by negating the pid
563 data->pid = -pid;
564 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
565
566 close(end_proc_detect[1]); // close writing side
567
568 wxBusyCursor bc;
569 wxWindowDisabler wd;
570
571 // it will be set to 0 from GTK_EndProcessDetector
572 while (data->pid != 0)
573 wxYield();
574
575 int exitcode = data->exitcode;
576
577 delete data;
578
579 return exitcode;
580 }
581 else // async execution
582 {
583 // async execution, nothing special to do - caller will be
584 // notified about the process termination if process != NULL, data
585 // will be deleted in GTK_EndProcessDetector
586 data->process = process;
587 data->pid = pid;
588 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
589
590 close(end_proc_detect[1]); // close writing side
591
592 return pid;
593 }
594 #else // !wxUSE_GUI
595 wxASSERT_MSG( sync, wxT("async execution not supported yet") );
596
597 int exitcode = 0;
598 if ( waitpid(pid, &exitcode, 0) == -1 || !WIFEXITED(exitcode) )
599 {
600 wxLogSysError(_("Waiting for subprocess termination failed"));
601 }
602
603 return exitcode;
604 #endif // wxUSE_GUI
605 }
606
607 return 0;
608
609 #undef ARGS_CLEANUP
610 }
611
612 // ----------------------------------------------------------------------------
613 // file and directory functions
614 // ----------------------------------------------------------------------------
615
616 const wxChar* wxGetHomeDir( wxString *home )
617 {
618 *home = wxGetUserHome( wxString() );
619 if ( home->IsEmpty() )
620 *home = wxT("/");
621
622 return home->c_str();
623 }
624
625 #if wxUSE_UNICODE
626 const wxMB2WXbuf wxGetUserHome( const wxString &user )
627 #else // just for binary compatibility -- there is no 'const' here
628 char *wxGetUserHome( const wxString &user )
629 #endif
630 {
631 struct passwd *who = (struct passwd *) NULL;
632
633 if ( !user )
634 {
635 wxChar *ptr;
636
637 if ((ptr = wxGetenv(wxT("HOME"))) != NULL)
638 {
639 return ptr;
640 }
641 if ((ptr = wxGetenv(wxT("USER"))) != NULL || (ptr = wxGetenv(wxT("LOGNAME"))) != NULL)
642 {
643 who = getpwnam(wxConvertWX2MB(ptr));
644 }
645
646 // We now make sure the the user exists!
647 if (who == NULL)
648 {
649 who = getpwuid(getuid());
650 }
651 }
652 else
653 {
654 who = getpwnam (user.mb_str());
655 }
656
657 return wxConvertMB2WX(who ? who->pw_dir : 0);
658 }
659
660 // ----------------------------------------------------------------------------
661 // network and user id routines
662 // ----------------------------------------------------------------------------
663
664 // retrieve either the hostname or FQDN depending on platform (caller must
665 // check whether it's one or the other, this is why this function is for
666 // private use only)
667 static bool wxGetHostNameInternal(wxChar *buf, int sz)
668 {
669 wxCHECK_MSG( buf, FALSE, wxT("NULL pointer in wxGetHostNameInternal") );
670
671 *buf = wxT('\0');
672
673 // we're using uname() which is POSIX instead of less standard sysinfo()
674 #if defined(HAVE_UNAME)
675 struct utsname uts;
676 bool ok = uname(&uts) != -1;
677 if ( ok )
678 {
679 wxStrncpy(buf, wxConvertMB2WX(uts.nodename), sz - 1);
680 buf[sz] = wxT('\0');
681 }
682 #elif defined(HAVE_GETHOSTNAME)
683 bool ok = gethostname(buf, sz) != -1;
684 #else // no uname, no gethostname
685 wxFAIL_MSG(wxT("don't know host name for this machine"));
686
687 bool ok = FALSE;
688 #endif // uname/gethostname
689
690 if ( !ok )
691 {
692 wxLogSysError(_("Cannot get the hostname"));
693 }
694
695 return ok;
696 }
697
698 bool wxGetHostName(wxChar *buf, int sz)
699 {
700 bool ok = wxGetHostNameInternal(buf, sz);
701
702 if ( ok )
703 {
704 // BSD systems return the FQDN, we only want the hostname, so extract
705 // it (we consider that dots are domain separators)
706 wxChar *dot = wxStrchr(buf, wxT('.'));
707 if ( dot )
708 {
709 // nuke it
710 *dot = wxT('\0');
711 }
712 }
713
714 return ok;
715 }
716
717 bool wxGetFullHostName(wxChar *buf, int sz)
718 {
719 bool ok = wxGetHostNameInternal(buf, sz);
720
721 if ( ok )
722 {
723 if ( !wxStrchr(buf, wxT('.')) )
724 {
725 struct hostent *host = gethostbyname(wxConvertWX2MB(buf));
726 if ( !host )
727 {
728 wxLogSysError(_("Cannot get the official hostname"));
729
730 ok = FALSE;
731 }
732 else
733 {
734 // the canonical name
735 wxStrncpy(buf, wxConvertMB2WX(host->h_name), sz);
736 }
737 }
738 //else: it's already a FQDN (BSD behaves this way)
739 }
740
741 return ok;
742 }
743
744 bool wxGetUserId(wxChar *buf, int sz)
745 {
746 struct passwd *who;
747
748 *buf = wxT('\0');
749 if ((who = getpwuid(getuid ())) != NULL)
750 {
751 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
752 return TRUE;
753 }
754
755 return FALSE;
756 }
757
758 bool wxGetUserName(wxChar *buf, int sz)
759 {
760 struct passwd *who;
761
762 *buf = wxT('\0');
763 if ((who = getpwuid (getuid ())) != NULL)
764 {
765 // pw_gecos field in struct passwd is not standard
766 #if HAVE_PW_GECOS
767 char *comma = strchr(who->pw_gecos, ',');
768 if (comma)
769 *comma = '\0'; // cut off non-name comment fields
770 wxStrncpy (buf, wxConvertMB2WX(who->pw_gecos), sz - 1);
771 #else // !HAVE_PW_GECOS
772 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
773 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
774 return TRUE;
775 }
776
777 return FALSE;
778 }
779
780 wxString wxGetOsDescription()
781 {
782 #ifndef WXWIN_OS_DESCRIPTION
783 #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
784 #else
785 return WXWIN_OS_DESCRIPTION;
786 #endif
787 }
788
789 // ----------------------------------------------------------------------------
790 // signal handling
791 // ----------------------------------------------------------------------------
792
793 #if wxUSE_ON_FATAL_EXCEPTION
794
795 #include <signal.h>
796
797 static void wxFatalSignalHandler(int signal)
798 {
799 if ( wxTheApp )
800 {
801 // give the user a chance to do something special about this
802 wxTheApp->OnFatalException();
803 }
804
805 abort();
806 }
807
808 bool wxHandleFatalExceptions(bool doit)
809 {
810 // old sig handlers
811 static bool s_savedHandlers = FALSE;
812 static struct sigaction s_handlerFPE,
813 s_handlerILL,
814 s_handlerBUS,
815 s_handlerSEGV;
816
817 bool ok = TRUE;
818 if ( doit && !s_savedHandlers )
819 {
820 // install the signal handler
821 struct sigaction act;
822
823 // some systems extend it with non std fields, so zero everything
824 memset(&act, 0, sizeof(act));
825
826 act.sa_handler = wxFatalSignalHandler;
827 sigemptyset(&act.sa_mask);
828 act.sa_flags = 0;
829
830 ok &= sigaction(SIGFPE, &act, &s_handlerFPE) == 0;
831 ok &= sigaction(SIGILL, &act, &s_handlerILL) == 0;
832 ok &= sigaction(SIGBUS, &act, &s_handlerBUS) == 0;
833 ok &= sigaction(SIGSEGV, &act, &s_handlerSEGV) == 0;
834 if ( !ok )
835 {
836 wxLogDebug(_T("Failed to install our signal handler."));
837 }
838
839 s_savedHandlers = TRUE;
840 }
841 else if ( s_savedHandlers )
842 {
843 // uninstall the signal handler
844 ok &= sigaction(SIGFPE, &s_handlerFPE, NULL) == 0;
845 ok &= sigaction(SIGILL, &s_handlerILL, NULL) == 0;
846 ok &= sigaction(SIGBUS, &s_handlerBUS, NULL) == 0;
847 ok &= sigaction(SIGSEGV, &s_handlerSEGV, NULL) == 0;
848 if ( !ok )
849 {
850 wxLogDebug(_T("Failed to uninstall our signal handler."));
851 }
852
853 s_savedHandlers = FALSE;
854 }
855 //else: nothing to do
856
857 return ok;
858 }
859
860 #endif // wxUSE_ON_FATAL_EXCEPTION
861
862 // ----------------------------------------------------------------------------
863 // error and debug output routines (deprecated, use wxLog)
864 // ----------------------------------------------------------------------------
865
866 void wxDebugMsg( const char *format, ... )
867 {
868 va_list ap;
869 va_start( ap, format );
870 vfprintf( stderr, format, ap );
871 fflush( stderr );
872 va_end(ap);
873 }
874
875 void wxError( const wxString &msg, const wxString &title )
876 {
877 wxFprintf( stderr, _("Error ") );
878 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
879 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
880 wxFprintf( stderr, wxT(".\n") );
881 }
882
883 void wxFatalError( const wxString &msg, const wxString &title )
884 {
885 wxFprintf( stderr, _("Error ") );
886 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
887 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
888 wxFprintf( stderr, wxT(".\n") );
889 exit(3); // the same exit code as for abort()
890 }
891