1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: generic Unix implementation of many wx functions
4 // Author: Vadim Zeitlin
6 // Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
19 #include "wx/string.h"
26 #include "wx/process.h"
27 #include "wx/thread.h"
29 #include "wx/stream.h"
36 #include "wx/unix/execute.h"
39 // SGI signal.h defines signal handler arguments differently depending on
40 // whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it
41 #if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS)
42 #define _LANGUAGE_C_PLUS_PLUS 1
49 #include <sys/types.h>
56 #include <fcntl.h> // for O_WRONLY and friends
57 #include <time.h> // nanosleep() and/or usleep()
58 #include <ctype.h> // isspace()
59 #include <sys/time.h> // needed for FD_SETSIZE
62 #include <sys/utsname.h> // for uname()
65 // ----------------------------------------------------------------------------
66 // conditional compilation
67 // ----------------------------------------------------------------------------
69 // many versions of Unices have this function, but it is not defined in system
70 // headers - please add your system here if it is the case for your OS.
71 // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
72 #if !defined(HAVE_USLEEP) && \
73 (defined(__SUN__) && !defined(__SunOs_5_6) && \
74 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
75 defined(__osf__) || defined(__EMX__)
79 int usleep(unsigned int usec
);
82 /* I copied this from the XFree86 diffs. AV. */
83 #define INCL_DOSPROCESS
85 inline void usleep(unsigned long delay
)
87 DosSleep(delay
? (delay
/1000l) : 1l);
90 void usleep(unsigned long usec
);
92 #endif // Sun/EMX/Something else
96 #endif // Unices without usleep()
98 // ============================================================================
100 // ============================================================================
102 // ----------------------------------------------------------------------------
104 // ----------------------------------------------------------------------------
106 void wxSleep(int nSecs
)
111 void wxUsleep(unsigned long milliseconds
)
113 #if defined(HAVE_NANOSLEEP)
115 tmReq
.tv_sec
= (time_t)(milliseconds
/ 1000);
116 tmReq
.tv_nsec
= (milliseconds
% 1000) * 1000 * 1000;
118 // we're not interested in remaining time nor in return value
119 (void)nanosleep(&tmReq
, (timespec
*)NULL
);
120 #elif defined(HAVE_USLEEP)
121 // uncomment this if you feel brave or if you are sure that your version
122 // of Solaris has a safe usleep() function but please notice that usleep()
123 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
124 // documented as MT-Safe
125 #if defined(__SUN__) && wxUSE_THREADS
126 #error "usleep() cannot be used in MT programs under Solaris."
129 usleep(milliseconds
* 1000); // usleep(3) wants microseconds
130 #elif defined(HAVE_SLEEP)
131 // under BeOS sleep() takes seconds (what about other platforms, if any?)
132 sleep(milliseconds
* 1000);
133 #else // !sleep function
134 #error "usleep() or nanosleep() function required for wxUsleep"
135 #endif // sleep function
138 // ----------------------------------------------------------------------------
139 // process management
140 // ----------------------------------------------------------------------------
142 int wxKill(long pid
, wxSignal sig
, wxKillError
*rc
)
144 int err
= kill((pid_t
)pid
, (int)sig
);
154 *rc
= wxKILL_BAD_SIGNAL
;
158 *rc
= wxKILL_ACCESS_DENIED
;
162 *rc
= wxKILL_NO_PROCESS
;
166 // this goes against Unix98 docs so log it
167 wxLogDebug(_T("unexpected kill(2) return value %d"), err
);
177 #define WXEXECUTE_NARGS 127
179 long wxExecute( const wxString
& command
, bool sync
, wxProcess
*process
)
181 wxCHECK_MSG( !command
.IsEmpty(), 0, wxT("can't exec empty command") );
184 wxChar
*argv
[WXEXECUTE_NARGS
];
186 const wxChar
*cptr
= command
.c_str();
187 wxChar quotechar
= wxT('\0'); // is arg quoted?
188 bool escaped
= FALSE
;
190 // split the command line in arguments
194 quotechar
= wxT('\0');
196 // eat leading whitespace:
197 while ( wxIsspace(*cptr
) )
200 if ( *cptr
== wxT('\'') || *cptr
== wxT('"') )
205 if ( *cptr
== wxT('\\') && ! escaped
)
212 // all other characters:
216 // have we reached the end of the argument?
217 if ( (*cptr
== quotechar
&& ! escaped
)
218 || (quotechar
== wxT('\0') && wxIsspace(*cptr
))
219 || *cptr
== wxT('\0') )
221 wxASSERT_MSG( argc
< WXEXECUTE_NARGS
,
222 wxT("too many arguments in wxExecute") );
224 argv
[argc
] = new wxChar
[argument
.length() + 1];
225 wxStrcpy(argv
[argc
], argument
.c_str());
228 // if not at end of buffer, swallow last character:
232 break; // done with this one, start over
238 // do execute the command
239 long lRc
= wxExecute(argv
, sync
, process
);
244 delete [] argv
[argc
++];
249 // ----------------------------------------------------------------------------
251 // ----------------------------------------------------------------------------
253 static wxString
wxMakeShellCommand(const wxString
& command
)
258 // just an interactive shell
263 // execute command in a shell
264 cmd
<< _T("/bin/sh -c '") << command
<< _T('\'');
270 bool wxShell(const wxString
& command
)
272 return wxExecute(wxMakeShellCommand(command
), TRUE
/* sync */) == 0;
275 bool wxShell(const wxString
& command
, wxArrayString
& output
)
277 wxCHECK_MSG( !!command
, FALSE
, _T("can't exec shell non interactively") );
279 return wxExecute(wxMakeShellCommand(command
), output
);
284 void wxHandleProcessTermination(wxEndProcessData
*proc_data
)
286 int pid
= (proc_data
->pid
> 0) ? proc_data
->pid
: -(proc_data
->pid
);
288 // waitpid is POSIX so should be available everywhere, however on older
289 // systems wait() might be used instead in a loop (until the right pid
294 // wait for child termination and if waitpid() was interrupted, try again
297 rc
= waitpid(pid
, &status
, 0);
299 while ( rc
== -1 && errno
== EINTR
);
303 // JACS: this could happen if the process was terminated and waitpid called,
304 // so commenting out for now.
305 //wxLogSysError(_("Waiting for subprocess termination failed (return code = -1)"));
307 else if (! (WIFEXITED(status
)))
309 wxLogSysError(_("Waiting for subprocess termination failed (WIFEXITED returned zero)"));
311 /* AFAIK, this can only happen if something went wrong within
312 wxGTK, i.e. due to a race condition or some serious bug.
313 After having fixed the order of statements in
314 GTK_EndProcessDetector(). (KB)
317 else if (WIFSIGNALED(status
))
319 wxLogSysError(_("Waiting for subprocess termination failed (signal not caught)"));
321 /* AFAIK, this can only happen if something went wrong within
322 wxGTK, i.e. due to a race condition or some serious bug.
323 After having fixed the order of statements in
324 GTK_EndProcessDetector(). (KB)
329 // notify user about termination if required
330 if (proc_data
->process
)
332 proc_data
->process
->OnTerminate(proc_data
->pid
,
333 WEXITSTATUS(status
));
336 if ( proc_data
->pid
> 0 )
342 // wxExecute() will know about it
343 proc_data
->exitcode
= status
;
352 // ----------------------------------------------------------------------------
353 // wxStream classes to support IO redirection in wxExecute
354 // ----------------------------------------------------------------------------
358 class wxProcessFileInputStream
: public wxInputStream
361 wxProcessFileInputStream(int fd
) { m_fd
= fd
; }
362 ~wxProcessFileInputStream() { close(m_fd
); }
364 virtual bool Eof() const;
367 size_t OnSysRead(void *buffer
, size_t bufsize
);
373 class wxProcessFileOutputStream
: public wxOutputStream
376 wxProcessFileOutputStream(int fd
) { m_fd
= fd
; }
377 ~wxProcessFileOutputStream() { close(m_fd
); }
380 size_t OnSysWrite(const void *buffer
, size_t bufsize
);
386 bool wxProcessFileInputStream::Eof() const
388 if ( m_lasterror
== wxSTREAM_EOF
)
391 // check if there is any input available
398 FD_SET(m_fd
, &readfds
);
399 switch ( select(m_fd
+ 1, &readfds
, NULL
, NULL
, &tv
) )
402 wxLogSysError(_("Impossible to get child process input"));
409 wxFAIL_MSG(_T("unexpected select() return value"));
410 // still fall through
413 // input available: check if there is any
414 return wxInputStream::Eof();
418 size_t wxProcessFileInputStream::OnSysRead(void *buffer
, size_t bufsize
)
420 int ret
= read(m_fd
, buffer
, bufsize
);
423 m_lasterror
= wxSTREAM_EOF
;
425 else if ( ret
== -1 )
427 m_lasterror
= wxSTREAM_READ_ERROR
;
432 m_lasterror
= wxSTREAM_NOERROR
;
438 size_t wxProcessFileOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
440 int ret
= write(m_fd
, buffer
, bufsize
);
443 m_lasterror
= wxSTREAM_WRITE_ERROR
;
448 m_lasterror
= wxSTREAM_NOERROR
;
454 // ----------------------------------------------------------------------------
455 // wxStreamTempBuffer
456 // ----------------------------------------------------------------------------
459 Extract of a mail to wx-users to give the context of the problem we are
460 trying to solve here:
462 MC> If I run the command:
463 MC> find . -name "*.h" -exec grep linux {} \;
464 MC> in the exec sample synchronously from the 'Capture command output'
465 MC> menu, wxExecute never returns. I have to xkill it. Has anyone
466 MC> else encountered this?
468 Yes, I can reproduce it too.
470 I even think I understand why it happens: before launching the external
471 command we set up a pipe with a valid file descriptor on the reading side
472 when the output is redirected. So the subprocess happily writes to it ...
473 until the pipe buffer (which is usually quite big on Unix, I think the
474 default is 4Mb) is full. Then the writing process stops and waits until we
475 read some data from the pipe to be able to continue writing to it but we
476 never do it because we wait until it terminates to start reading and so we
477 have a classical deadlock.
479 Here is the fix: we now read the output as soon as it appears into a temp
480 buffer (wxStreamTempBuffer object) and later just stuff it back into the
481 stream when the process terminates. See supporting code in wxExecute()
485 class wxStreamTempBuffer
488 wxStreamTempBuffer();
490 // call to associate a stream with this buffer, otherwise nothing happens
492 void Init(wxInputStream
*stream
);
494 // check for input on our stream and cache it in our buffer if any
497 ~wxStreamTempBuffer();
500 // the stream we're buffering, if NULL we don't do anything at all
501 wxInputStream
*m_stream
;
503 // the buffer of size m_size (NULL if m_size == 0)
506 // the size of the buffer
510 wxStreamTempBuffer::wxStreamTempBuffer()
517 void wxStreamTempBuffer::Init(wxInputStream
*stream
)
522 void wxStreamTempBuffer::Update()
524 if ( m_stream
&& !m_stream
->Eof() )
526 // realloc in blocks of 1Kb - surely not the best strategy but which
528 static const size_t incSize
= 1024;
530 void *buf
= realloc(m_buffer
, m_size
+ incSize
);
533 // don't read any more, we don't have enough memory to do it
536 else // got memory for the buffer
539 m_stream
->Read((char *)m_buffer
+ m_size
, incSize
);
545 wxStreamTempBuffer::~wxStreamTempBuffer()
549 m_stream
->Ungetch(m_buffer
, m_size
);
554 #endif // wxUSE_STREAMS
556 long wxExecute(wxChar
**argv
,
560 // for the sync execution, we return -1 to indicate failure, but for async
561 // case we return 0 which is never a valid PID
563 // we define this as a macro, not a variable, to avoid compiler warnings
564 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
565 #define ERROR_RETURN_CODE ((sync) ? -1 : 0)
567 wxCHECK_MSG( *argv
, ERROR_RETURN_CODE
, wxT("can't exec empty command") );
571 char *mb_argv
[WXEXECUTE_NARGS
];
573 while (argv
[mb_argc
])
575 wxWX2MBbuf mb_arg
= wxConvertWX2MB(argv
[mb_argc
]);
576 mb_argv
[mb_argc
] = strdup(mb_arg
);
579 mb_argv
[mb_argc
] = (char *) NULL
;
581 // this macro will free memory we used above
582 #define ARGS_CLEANUP \
583 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
584 free(mb_argv[mb_argc])
586 // no need for cleanup
589 wxChar
**mb_argv
= argv
;
590 #endif // Unicode/ANSI
594 int end_proc_detect
[2];
595 if ( pipe(end_proc_detect
) == -1 )
597 wxLogSysError( _("Pipe creation failed") );
598 wxLogError( _("Failed to execute '%s'\n"), *argv
);
602 return ERROR_RETURN_CODE
;
606 // pipes for inter process communication
607 int pipeIn
[2], // stdin
608 pipeOut
[2], // stdout
609 pipeErr
[2]; // stderr
611 pipeIn
[0] = pipeIn
[1] =
612 pipeOut
[0] = pipeOut
[1] =
613 pipeErr
[0] = pipeErr
[1] = -1;
615 if ( process
&& process
->IsRedirected() )
617 if ( pipe(pipeIn
) == -1 || pipe(pipeOut
) == -1 || pipe(pipeErr
) == -1 )
620 // free previously allocated resources
621 close(end_proc_detect
[0]);
622 close(end_proc_detect
[1]);
625 wxLogSysError( _("Pipe creation failed") );
626 wxLogError( _("Failed to execute '%s'\n"), *argv
);
630 return ERROR_RETURN_CODE
;
641 if ( pid
== -1 ) // error?
644 close(end_proc_detect
[0]);
645 close(end_proc_detect
[1]);
654 wxLogSysError( _("Fork failed") );
658 return ERROR_RETURN_CODE
;
660 else if ( pid
== 0 ) // we're in child
663 close(end_proc_detect
[0]); // close reading side
666 // These lines close the open file descriptors to to avoid any
667 // input/output which might block the process or irritate the user. If
668 // one wants proper IO for the subprocess, the right thing to do is to
669 // start an xterm executing it.
672 for ( int fd
= 0; fd
< FD_SETSIZE
; fd
++ )
674 if ( fd
== pipeIn
[0] || fd
== pipeOut
[1] || fd
== pipeErr
[1]
676 || fd
== end_proc_detect
[1]
680 // don't close this one, we still need it
684 // leave stderr opened too, it won't do any hurm
685 if ( fd
!= STDERR_FILENO
)
690 // redirect stdio, stdout and stderr
691 if ( pipeIn
[0] != -1 )
693 if ( dup2(pipeIn
[0], STDIN_FILENO
) == -1 ||
694 dup2(pipeOut
[1], STDOUT_FILENO
) == -1 ||
695 dup2(pipeErr
[1], STDERR_FILENO
) == -1 )
697 wxLogSysError(_("Failed to redirect child process input/output"));
705 execvp (*mb_argv
, mb_argv
);
707 // there is no return after successful exec()
710 // some compilers complain about missing return - of course, they
711 // should know that exit() doesn't return but what else can we do if
713 #if defined(__VMS) || defined(__INTEL_COMPILER)
717 else // we're in parent
721 // pipe initialization: construction of the wxStreams
723 wxStreamTempBuffer bufIn
, bufErr
;
724 #endif // wxUSE_STREAMS
726 if ( process
&& process
->IsRedirected() )
729 // in/out for subprocess correspond to our out/in
730 wxOutputStream
*outStream
= new wxProcessFileOutputStream(pipeIn
[1]);
731 wxInputStream
*inStream
= new wxProcessFileInputStream(pipeOut
[0]);
732 wxInputStream
*errStream
= new wxProcessFileInputStream(pipeErr
[0]);
734 process
->SetPipeStreams(inStream
, outStream
, errStream
);
736 bufIn
.Init(inStream
);
737 bufErr
.Init(inStream
);
738 #endif // wxUSE_STREAMS
740 close(pipeIn
[0]); // close reading side
741 close(pipeOut
[1]); // close writing side
742 close(pipeErr
[1]); // close writing side
745 #if wxUSE_GUI && !defined(__WXMICROWIN__)
746 wxEndProcessData
*data
= new wxEndProcessData
;
750 // we may have process for capturing the program output, but it's
751 // not used in wxEndProcessData in the case of sync execution
752 data
->process
= NULL
;
754 // sync execution: indicate it by negating the pid
756 data
->tag
= wxAddProcessCallback(data
, end_proc_detect
[0]);
758 close(end_proc_detect
[1]); // close writing side
763 // data->pid will be set to 0 from GTK_EndProcessDetector when the
764 // process terminates
765 while ( data
->pid
!= 0 )
770 #endif // wxUSE_STREAMS
772 // give GTK+ a chance to call GTK_EndProcessDetector here and
773 // also repaint the GUI
777 int exitcode
= data
->exitcode
;
783 else // async execution
785 // async execution, nothing special to do - caller will be
786 // notified about the process termination if process != NULL, data
787 // will be deleted in GTK_EndProcessDetector
788 data
->process
= process
;
790 data
->tag
= wxAddProcessCallback(data
, end_proc_detect
[0]);
792 close(end_proc_detect
[1]); // close writing side
797 wxASSERT_MSG( sync
, wxT("async execution not supported yet") );
800 if ( waitpid(pid
, &exitcode
, 0) == -1 || !WIFEXITED(exitcode
) )
802 wxLogSysError(_("Waiting for subprocess termination failed"));
810 #undef ERROR_RETURN_CODE
813 // ----------------------------------------------------------------------------
814 // file and directory functions
815 // ----------------------------------------------------------------------------
817 const wxChar
* wxGetHomeDir( wxString
*home
)
819 *home
= wxGetUserHome( wxString() );
821 if ( home
->IsEmpty() )
825 if ( tmp
.Last() != wxT(']'))
826 if ( tmp
.Last() != wxT('/')) *home
<< wxT('/');
828 return home
->c_str();
832 const wxMB2WXbuf
wxGetUserHome( const wxString
&user
)
833 #else // just for binary compatibility -- there is no 'const' here
834 char *wxGetUserHome( const wxString
&user
)
837 struct passwd
*who
= (struct passwd
*) NULL
;
843 if ((ptr
= wxGetenv(wxT("HOME"))) != NULL
)
847 if ((ptr
= wxGetenv(wxT("USER"))) != NULL
|| (ptr
= wxGetenv(wxT("LOGNAME"))) != NULL
)
849 who
= getpwnam(wxConvertWX2MB(ptr
));
852 // We now make sure the the user exists!
855 who
= getpwuid(getuid());
860 who
= getpwnam (user
.mb_str());
863 return wxConvertMB2WX(who
? who
->pw_dir
: 0);
866 // ----------------------------------------------------------------------------
867 // network and user id routines
868 // ----------------------------------------------------------------------------
870 // retrieve either the hostname or FQDN depending on platform (caller must
871 // check whether it's one or the other, this is why this function is for
873 static bool wxGetHostNameInternal(wxChar
*buf
, int sz
)
875 wxCHECK_MSG( buf
, FALSE
, wxT("NULL pointer in wxGetHostNameInternal") );
879 // we're using uname() which is POSIX instead of less standard sysinfo()
880 #if defined(HAVE_UNAME)
882 bool ok
= uname(&uts
) != -1;
885 wxStrncpy(buf
, wxConvertMB2WX(uts
.nodename
), sz
- 1);
888 #elif defined(HAVE_GETHOSTNAME)
889 bool ok
= gethostname(buf
, sz
) != -1;
890 #else // no uname, no gethostname
891 wxFAIL_MSG(wxT("don't know host name for this machine"));
894 #endif // uname/gethostname
898 wxLogSysError(_("Cannot get the hostname"));
904 bool wxGetHostName(wxChar
*buf
, int sz
)
906 bool ok
= wxGetHostNameInternal(buf
, sz
);
910 // BSD systems return the FQDN, we only want the hostname, so extract
911 // it (we consider that dots are domain separators)
912 wxChar
*dot
= wxStrchr(buf
, wxT('.'));
923 bool wxGetFullHostName(wxChar
*buf
, int sz
)
925 bool ok
= wxGetHostNameInternal(buf
, sz
);
929 if ( !wxStrchr(buf
, wxT('.')) )
931 struct hostent
*host
= gethostbyname(wxConvertWX2MB(buf
));
934 wxLogSysError(_("Cannot get the official hostname"));
940 // the canonical name
941 wxStrncpy(buf
, wxConvertMB2WX(host
->h_name
), sz
);
944 //else: it's already a FQDN (BSD behaves this way)
950 bool wxGetUserId(wxChar
*buf
, int sz
)
955 if ((who
= getpwuid(getuid ())) != NULL
)
957 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz
- 1);
964 bool wxGetUserName(wxChar
*buf
, int sz
)
969 if ((who
= getpwuid (getuid ())) != NULL
)
971 // pw_gecos field in struct passwd is not standard
973 char *comma
= strchr(who
->pw_gecos
, ',');
975 *comma
= '\0'; // cut off non-name comment fields
976 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_gecos
), sz
- 1);
977 #else // !HAVE_PW_GECOS
978 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz
- 1);
979 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
986 wxString
wxGetOsDescription()
988 #ifndef WXWIN_OS_DESCRIPTION
989 #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
991 return WXWIN_OS_DESCRIPTION
;
995 // this function returns the GUI toolkit version in GUI programs, but OS
996 // version in non-GUI ones
999 int wxGetOsVersion(int *majorVsn
, int *minorVsn
)
1004 if ( sscanf(WXWIN_OS_DESCRIPTION
, "%s %d.%d", name
, &major
, &minor
) != 3 )
1006 // unreckognized uname string format
1018 #endif // !wxUSE_GUI
1020 long wxGetFreeMemory()
1022 #if defined(__LINUX__)
1023 // get it from /proc/meminfo
1024 FILE *fp
= fopen("/proc/meminfo", "r");
1030 if ( fgets(buf
, WXSIZEOF(buf
), fp
) && fgets(buf
, WXSIZEOF(buf
), fp
) )
1032 long memTotal
, memUsed
;
1033 sscanf(buf
, "Mem: %ld %ld %ld", &memTotal
, &memUsed
, &memFree
);
1040 #elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES)
1041 return sysconf(_SC_AVPHYS_PAGES
)*sysconf(_SC_PAGESIZE
);
1042 //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1045 // can't find it out
1049 bool wxGetDiskSpace(const wxString
& path
, wxLongLong
*pTotal
, wxLongLong
*pFree
)
1054 if ( statfs(path
, &fs
) != 0 )
1056 wxLogSysError("Failed to get file system statistics");
1063 *pTotal
= wxLongLong(fs
.f_blocks
) * fs
.f_bsize
;
1068 *pFree
= wxLongLong(fs
.f_bavail
) * fs
.f_bsize
;
1072 #endif // HAVE_STATFS
1077 // ----------------------------------------------------------------------------
1079 // ----------------------------------------------------------------------------
1081 bool wxGetEnv(const wxString
& var
, wxString
*value
)
1083 // wxGetenv is defined as getenv()
1084 wxChar
*p
= wxGetenv(var
);
1096 bool wxSetEnv(const wxString
& variable
, const wxChar
*value
)
1098 #if defined(HAVE_SETENV)
1099 return setenv(variable
.mb_str(), value
? wxString(value
).mb_str().data()
1100 : NULL
, 1 /* overwrite */) == 0;
1101 #elif defined(HAVE_PUTENV)
1102 wxString s
= variable
;
1104 s
<< _T('=') << value
;
1106 // transform to ANSI
1107 const char *p
= s
.mb_str();
1109 // the string will be free()d by libc
1110 char *buf
= (char *)malloc(strlen(p
) + 1);
1113 return putenv(buf
) == 0;
1114 #else // no way to set an env var
1119 // ----------------------------------------------------------------------------
1121 // ----------------------------------------------------------------------------
1123 #if wxUSE_ON_FATAL_EXCEPTION
1127 static void wxFatalSignalHandler(wxTYPE_SA_HANDLER
)
1131 // give the user a chance to do something special about this
1132 wxTheApp
->OnFatalException();
1138 bool wxHandleFatalExceptions(bool doit
)
1141 static bool s_savedHandlers
= FALSE
;
1142 static struct sigaction s_handlerFPE
,
1148 if ( doit
&& !s_savedHandlers
)
1150 // install the signal handler
1151 struct sigaction act
;
1153 // some systems extend it with non std fields, so zero everything
1154 memset(&act
, 0, sizeof(act
));
1156 act
.sa_handler
= wxFatalSignalHandler
;
1157 sigemptyset(&act
.sa_mask
);
1160 ok
&= sigaction(SIGFPE
, &act
, &s_handlerFPE
) == 0;
1161 ok
&= sigaction(SIGILL
, &act
, &s_handlerILL
) == 0;
1162 ok
&= sigaction(SIGBUS
, &act
, &s_handlerBUS
) == 0;
1163 ok
&= sigaction(SIGSEGV
, &act
, &s_handlerSEGV
) == 0;
1166 wxLogDebug(_T("Failed to install our signal handler."));
1169 s_savedHandlers
= TRUE
;
1171 else if ( s_savedHandlers
)
1173 // uninstall the signal handler
1174 ok
&= sigaction(SIGFPE
, &s_handlerFPE
, NULL
) == 0;
1175 ok
&= sigaction(SIGILL
, &s_handlerILL
, NULL
) == 0;
1176 ok
&= sigaction(SIGBUS
, &s_handlerBUS
, NULL
) == 0;
1177 ok
&= sigaction(SIGSEGV
, &s_handlerSEGV
, NULL
) == 0;
1180 wxLogDebug(_T("Failed to uninstall our signal handler."));
1183 s_savedHandlers
= FALSE
;
1185 //else: nothing to do
1190 #endif // wxUSE_ON_FATAL_EXCEPTION
1192 // ----------------------------------------------------------------------------
1193 // error and debug output routines (deprecated, use wxLog)
1194 // ----------------------------------------------------------------------------
1196 void wxDebugMsg( const char *format
, ... )
1199 va_start( ap
, format
);
1200 vfprintf( stderr
, format
, ap
);
1205 void wxError( const wxString
&msg
, const wxString
&title
)
1207 wxFprintf( stderr
, _("Error ") );
1208 if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) );
1209 if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) );
1210 wxFprintf( stderr
, wxT(".\n") );
1213 void wxFatalError( const wxString
&msg
, const wxString
&title
)
1215 wxFprintf( stderr
, _("Error ") );
1216 if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) );
1217 if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) );
1218 wxFprintf( stderr
, wxT(".\n") );
1219 exit(3); // the same exit code as for abort()