///////////////////////////////////////////////////////////////////////////// // Name: utilsunx.cpp // Purpose: generic Unix implementation of many wx functions // Author: Vadim Zeitlin // Id: $Id$ // Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // ============================================================================ // declarations // ============================================================================ // ---------------------------------------------------------------------------- // headers // ---------------------------------------------------------------------------- #include "wx/defs.h" #include "wx/string.h" #include "wx/intl.h" #include "wx/log.h" #include "wx/app.h" #include "wx/utils.h" #include "wx/process.h" #include "wx/thread.h" #include "wx/stream.h" #ifdef HAVE_STATFS # ifdef __DARWIN__ # include # include # else # include # endif #endif // HAVE_STATFS #if wxUSE_GUI #include "wx/unix/execute.h" #endif // SGI signal.h defines signal handler arguments differently depending on // whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it #if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS) #define _LANGUAGE_C_PLUS_PLUS 1 #endif // SGI hack #include #include #include #include #include #include #include #include #include #include #include #include // for O_WRONLY and friends #include // nanosleep() and/or usleep() #include // isspace() #include // needed for FD_SETSIZE #ifdef HAVE_UNAME #include // for uname() #endif // HAVE_UNAME // ---------------------------------------------------------------------------- // conditional compilation // ---------------------------------------------------------------------------- // many versions of Unices have this function, but it is not defined in system // headers - please add your system here if it is the case for your OS. // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this. #if !defined(HAVE_USLEEP) && \ (defined(__SUN__) && !defined(__SunOs_5_6) && \ !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \ defined(__osf__) || defined(__EMX__) extern "C" { #ifdef __SUN__ int usleep(unsigned int usec); #else // !Sun #ifdef __EMX__ /* I copied this from the XFree86 diffs. AV. */ #define INCL_DOSPROCESS #include inline void usleep(unsigned long delay) { DosSleep(delay ? (delay/1000l) : 1l); } #else // !Sun && !EMX void usleep(unsigned long usec); #endif #endif // Sun/EMX/Something else }; #define HAVE_USLEEP 1 #endif // Unices without usleep() // ============================================================================ // implementation // ============================================================================ // ---------------------------------------------------------------------------- // sleeping // ---------------------------------------------------------------------------- void wxSleep(int nSecs) { sleep(nSecs); } void wxUsleep(unsigned long milliseconds) { #if defined(HAVE_NANOSLEEP) timespec tmReq; tmReq.tv_sec = (time_t)(milliseconds / 1000); tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000; // we're not interested in remaining time nor in return value (void)nanosleep(&tmReq, (timespec *)NULL); #elif defined(HAVE_USLEEP) // uncomment this if you feel brave or if you are sure that your version // of Solaris has a safe usleep() function but please notice that usleep() // is known to lead to crashes in MT programs in Solaris 2.[67] and is not // documented as MT-Safe #if defined(__SUN__) && wxUSE_THREADS #error "usleep() cannot be used in MT programs under Solaris." #endif // Sun usleep(milliseconds * 1000); // usleep(3) wants microseconds #elif defined(HAVE_SLEEP) // under BeOS sleep() takes seconds (what about other platforms, if any?) sleep(milliseconds * 1000); #else // !sleep function #error "usleep() or nanosleep() function required for wxUsleep" #endif // sleep function } // ---------------------------------------------------------------------------- // process management // ---------------------------------------------------------------------------- int wxKill(long pid, wxSignal sig, wxKillError *rc) { int err = kill((pid_t)pid, (int)sig); if ( rc ) { switch ( err ) { case 0: *rc = wxKILL_OK; break; case EINVAL: *rc = wxKILL_BAD_SIGNAL; break; case EPERM: *rc = wxKILL_ACCESS_DENIED; break; case ESRCH: *rc = wxKILL_NO_PROCESS; break; default: // this goes against Unix98 docs so log it wxLogDebug(_T("unexpected kill(2) return value %d"), err); // something else... *rc = wxKILL_ERROR; } } return err; } #define WXEXECUTE_NARGS 127 long wxExecute( const wxString& command, bool sync, wxProcess *process ) { wxCHECK_MSG( !command.IsEmpty(), 0, wxT("can't exec empty command") ); int argc = 0; wxChar *argv[WXEXECUTE_NARGS]; wxString argument; const wxChar *cptr = command.c_str(); wxChar quotechar = wxT('\0'); // is arg quoted? bool escaped = FALSE; // split the command line in arguments do { argument=wxT(""); quotechar = wxT('\0'); // eat leading whitespace: while ( wxIsspace(*cptr) ) cptr++; if ( *cptr == wxT('\'') || *cptr == wxT('"') ) quotechar = *cptr++; do { if ( *cptr == wxT('\\') && ! escaped ) { escaped = TRUE; cptr++; continue; } // all other characters: argument += *cptr++; escaped = FALSE; // have we reached the end of the argument? if ( (*cptr == quotechar && ! escaped) || (quotechar == wxT('\0') && wxIsspace(*cptr)) || *cptr == wxT('\0') ) { wxASSERT_MSG( argc < WXEXECUTE_NARGS, wxT("too many arguments in wxExecute") ); argv[argc] = new wxChar[argument.length() + 1]; wxStrcpy(argv[argc], argument.c_str()); argc++; // if not at end of buffer, swallow last character: if(*cptr) cptr++; break; // done with this one, start over } } while(*cptr); } while(*cptr); argv[argc] = NULL; // do execute the command long lRc = wxExecute(argv, sync, process); // clean up argc = 0; while( argv[argc] ) delete [] argv[argc++]; return lRc; } // ---------------------------------------------------------------------------- // wxShell // ---------------------------------------------------------------------------- static wxString wxMakeShellCommand(const wxString& command) { wxString cmd; if ( !command ) { // just an interactive shell cmd = _T("xterm"); } else { // execute command in a shell cmd << _T("/bin/sh -c '") << command << _T('\''); } return cmd; } bool wxShell(const wxString& command) { return wxExecute(wxMakeShellCommand(command), TRUE /* sync */) == 0; } bool wxShell(const wxString& command, wxArrayString& output) { wxCHECK_MSG( !!command, FALSE, _T("can't exec shell non interactively") ); return wxExecute(wxMakeShellCommand(command), output); } #if wxUSE_GUI void wxHandleProcessTermination(wxEndProcessData *proc_data) { // notify user about termination if required if ( proc_data->process ) { proc_data->process->OnTerminate(proc_data->pid, proc_data->exitcode); } // clean up if ( proc_data->pid > 0 ) { delete proc_data; } else { // let wxExecute() know that the process has terminated proc_data->pid = 0; } } #endif // wxUSE_GUI // ---------------------------------------------------------------------------- // wxStream classes to support IO redirection in wxExecute // ---------------------------------------------------------------------------- #if wxUSE_STREAMS class wxProcessFileInputStream : public wxInputStream { public: wxProcessFileInputStream(int fd) { m_fd = fd; } ~wxProcessFileInputStream() { close(m_fd); } virtual bool Eof() const; protected: size_t OnSysRead(void *buffer, size_t bufsize); protected: int m_fd; }; class wxProcessFileOutputStream : public wxOutputStream { public: wxProcessFileOutputStream(int fd) { m_fd = fd; } ~wxProcessFileOutputStream() { close(m_fd); } protected: size_t OnSysWrite(const void *buffer, size_t bufsize); protected: int m_fd; }; bool wxProcessFileInputStream::Eof() const { if ( m_lasterror == wxSTREAM_EOF ) return TRUE; // check if there is any input available struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; fd_set readfds; FD_ZERO(&readfds); FD_SET(m_fd, &readfds); switch ( select(m_fd + 1, &readfds, NULL, NULL, &tv) ) { case -1: wxLogSysError(_("Impossible to get child process input")); // fall through case 0: return TRUE; default: wxFAIL_MSG(_T("unexpected select() return value")); // still fall through case 1: // input available: check if there is any return wxInputStream::Eof(); } } size_t wxProcessFileInputStream::OnSysRead(void *buffer, size_t bufsize) { int ret = read(m_fd, buffer, bufsize); if ( ret == 0 ) { m_lasterror = wxSTREAM_EOF; } else if ( ret == -1 ) { m_lasterror = wxSTREAM_READ_ERROR; ret = 0; } else { m_lasterror = wxSTREAM_NOERROR; } return ret; } size_t wxProcessFileOutputStream::OnSysWrite(const void *buffer, size_t bufsize) { int ret = write(m_fd, buffer, bufsize); if ( ret == -1 ) { m_lasterror = wxSTREAM_WRITE_ERROR; ret = 0; } else { m_lasterror = wxSTREAM_NOERROR; } return ret; } // ---------------------------------------------------------------------------- // wxStreamTempBuffer // ---------------------------------------------------------------------------- /* Extract of a mail to wx-users to give the context of the problem we are trying to solve here: MC> If I run the command: MC> find . -name "*.h" -exec grep linux {} \; MC> in the exec sample synchronously from the 'Capture command output' MC> menu, wxExecute never returns. I have to xkill it. Has anyone MC> else encountered this? Yes, I can reproduce it too. I even think I understand why it happens: before launching the external command we set up a pipe with a valid file descriptor on the reading side when the output is redirected. So the subprocess happily writes to it ... until the pipe buffer (which is usually quite big on Unix, I think the default is 4Mb) is full. Then the writing process stops and waits until we read some data from the pipe to be able to continue writing to it but we never do it because we wait until it terminates to start reading and so we have a classical deadlock. Here is the fix: we now read the output as soon as it appears into a temp buffer (wxStreamTempBuffer object) and later just stuff it back into the stream when the process terminates. See supporting code in wxExecute() itself as well. */ class wxStreamTempBuffer { public: wxStreamTempBuffer(); // call to associate a stream with this buffer, otherwise nothing happens // at all void Init(wxInputStream *stream); // check for input on our stream and cache it in our buffer if any void Update(); ~wxStreamTempBuffer(); private: // the stream we're buffering, if NULL we don't do anything at all wxInputStream *m_stream; // the buffer of size m_size (NULL if m_size == 0) void *m_buffer; // the size of the buffer size_t m_size; }; wxStreamTempBuffer::wxStreamTempBuffer() { m_stream = NULL; m_buffer = NULL; m_size = 0; } void wxStreamTempBuffer::Init(wxInputStream *stream) { m_stream = stream; } void wxStreamTempBuffer::Update() { if ( m_stream && !m_stream->Eof() ) { // realloc in blocks of 1Kb - surely not the best strategy but which // one is? static const size_t incSize = 1024; void *buf = realloc(m_buffer, m_size + incSize); if ( !buf ) { // don't read any more, we don't have enough memory to do it m_stream = NULL; } else // got memory for the buffer { m_buffer = buf; m_stream->Read((char *)m_buffer + m_size, incSize); m_size += incSize; } } } wxStreamTempBuffer::~wxStreamTempBuffer() { if ( m_buffer ) { m_stream->Ungetch(m_buffer, m_size); free(m_buffer); } } #endif // wxUSE_STREAMS long wxExecute(wxChar **argv, bool sync, wxProcess *process) { // for the sync execution, we return -1 to indicate failure, but for async // case we return 0 which is never a valid PID // // we define this as a macro, not a variable, to avoid compiler warnings // about "ERROR_RETURN_CODE value may be clobbered by fork()" #define ERROR_RETURN_CODE ((sync) ? -1 : 0) wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") ); #if wxUSE_UNICODE int mb_argc = 0; char *mb_argv[WXEXECUTE_NARGS]; while (argv[mb_argc]) { wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]); mb_argv[mb_argc] = strdup(mb_arg); mb_argc++; } mb_argv[mb_argc] = (char *) NULL; // this macro will free memory we used above #define ARGS_CLEANUP \ for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \ free(mb_argv[mb_argc]) #else // ANSI // no need for cleanup #define ARGS_CLEANUP wxChar **mb_argv = argv; #endif // Unicode/ANSI #if wxUSE_GUI // create pipes int end_proc_detect[2]; if ( pipe(end_proc_detect) == -1 ) { wxLogSysError( _("Pipe creation failed") ); wxLogError( _("Failed to execute '%s'\n"), *argv ); ARGS_CLEANUP; return ERROR_RETURN_CODE; } #endif // wxUSE_GUI // pipes for inter process communication int pipeIn[2], // stdin pipeOut[2], // stdout pipeErr[2]; // stderr pipeIn[0] = pipeIn[1] = pipeOut[0] = pipeOut[1] = pipeErr[0] = pipeErr[1] = -1; if ( process && process->IsRedirected() ) { if ( pipe(pipeIn) == -1 || pipe(pipeOut) == -1 || pipe(pipeErr) == -1 ) { #if wxUSE_GUI // free previously allocated resources close(end_proc_detect[0]); close(end_proc_detect[1]); #endif // wxUSE_GUI wxLogSysError( _("Pipe creation failed") ); wxLogError( _("Failed to execute '%s'\n"), *argv ); ARGS_CLEANUP; return ERROR_RETURN_CODE; } } // fork the process #ifdef HAVE_VFORK pid_t pid = vfork(); #else pid_t pid = fork(); #endif if ( pid == -1 ) // error? { #if wxUSE_GUI close(end_proc_detect[0]); close(end_proc_detect[1]); close(pipeIn[0]); close(pipeIn[1]); close(pipeOut[0]); close(pipeOut[1]); close(pipeErr[0]); close(pipeErr[1]); #endif // wxUSE_GUI wxLogSysError( _("Fork failed") ); ARGS_CLEANUP; return ERROR_RETURN_CODE; } else if ( pid == 0 ) // we're in child { #if wxUSE_GUI close(end_proc_detect[0]); // close reading side #endif // wxUSE_GUI // These lines close the open file descriptors to to avoid any // input/output which might block the process or irritate the user. If // one wants proper IO for the subprocess, the right thing to do is to // start an xterm executing it. if ( !sync ) { for ( int fd = 0; fd < FD_SETSIZE; fd++ ) { if ( fd == pipeIn[0] || fd == pipeOut[1] || fd == pipeErr[1] #if wxUSE_GUI || fd == end_proc_detect[1] #endif // wxUSE_GUI ) { // don't close this one, we still need it continue; } // leave stderr opened too, it won't do any hurm if ( fd != STDERR_FILENO ) close(fd); } } // redirect stdio, stdout and stderr if ( pipeIn[0] != -1 ) { if ( dup2(pipeIn[0], STDIN_FILENO) == -1 || dup2(pipeOut[1], STDOUT_FILENO) == -1 || dup2(pipeErr[1], STDERR_FILENO) == -1 ) { wxLogSysError(_("Failed to redirect child process input/output")); } close(pipeIn[0]); close(pipeOut[1]); close(pipeErr[1]); } execvp (*mb_argv, mb_argv); // there is no return after successful exec() _exit(-1); // some compilers complain about missing return - of course, they // should know that exit() doesn't return but what else can we do if // they don't? #if defined(__VMS) || defined(__INTEL_COMPILER) return 0; #endif } else // we're in parent { ARGS_CLEANUP; // pipe initialization: construction of the wxStreams #if wxUSE_STREAMS wxStreamTempBuffer bufIn, bufErr; #endif // wxUSE_STREAMS if ( process && process->IsRedirected() ) { #if wxUSE_STREAMS // in/out for subprocess correspond to our out/in wxOutputStream *outStream = new wxProcessFileOutputStream(pipeIn[1]); wxInputStream *inStream = new wxProcessFileInputStream(pipeOut[0]); wxInputStream *errStream = new wxProcessFileInputStream(pipeErr[0]); process->SetPipeStreams(inStream, outStream, errStream); bufIn.Init(inStream); bufErr.Init(inStream); #endif // wxUSE_STREAMS close(pipeIn[0]); // close reading side close(pipeOut[1]); // close writing side close(pipeErr[1]); // close writing side } #if wxUSE_GUI && !defined(__WXMICROWIN__) wxEndProcessData *data = new wxEndProcessData; if ( sync ) { // we may have process for capturing the program output, but it's // not used in wxEndProcessData in the case of sync execution data->process = NULL; // sync execution: indicate it by negating the pid data->pid = -pid; data->tag = wxAddProcessCallback(data, end_proc_detect[0]); close(end_proc_detect[1]); // close writing side wxBusyCursor bc; wxWindowDisabler wd; // data->pid will be set to 0 from GTK_EndProcessDetector when the // process terminates while ( data->pid != 0 ) { #if wxUSE_STREAMS bufIn.Update(); bufErr.Update(); #endif // wxUSE_STREAMS // give GTK+ a chance to call GTK_EndProcessDetector here and // also repaint the GUI wxYield(); } int exitcode = data->exitcode; delete data; return exitcode; } else // async execution { // async execution, nothing special to do - caller will be // notified about the process termination if process != NULL, data // will be deleted in GTK_EndProcessDetector data->process = process; data->pid = pid; data->tag = wxAddProcessCallback(data, end_proc_detect[0]); close(end_proc_detect[1]); // close writing side return pid; } #else // !wxUSE_GUI wxASSERT_MSG( sync, wxT("async execution not supported yet") ); int exitcode = 0; if ( waitpid(pid, &exitcode, 0) == -1 || !WIFEXITED(exitcode) ) { wxLogSysError(_("Waiting for subprocess termination failed")); } return exitcode; #endif // wxUSE_GUI } } #undef ERROR_RETURN_CODE #undef ARGS_CLEANUP // ---------------------------------------------------------------------------- // file and directory functions // ---------------------------------------------------------------------------- const wxChar* wxGetHomeDir( wxString *home ) { *home = wxGetUserHome( wxString() ); wxString tmp; if ( home->IsEmpty() ) *home = wxT("/"); #ifdef __VMS tmp = *home; if ( tmp.Last() != wxT(']')) if ( tmp.Last() != wxT('/')) *home << wxT('/'); #endif return home->c_str(); } #if wxUSE_UNICODE const wxMB2WXbuf wxGetUserHome( const wxString &user ) #else // just for binary compatibility -- there is no 'const' here char *wxGetUserHome( const wxString &user ) #endif { struct passwd *who = (struct passwd *) NULL; if ( !user ) { wxChar *ptr; if ((ptr = wxGetenv(wxT("HOME"))) != NULL) { return ptr; } if ((ptr = wxGetenv(wxT("USER"))) != NULL || (ptr = wxGetenv(wxT("LOGNAME"))) != NULL) { who = getpwnam(wxConvertWX2MB(ptr)); } // We now make sure the the user exists! if (who == NULL) { who = getpwuid(getuid()); } } else { who = getpwnam (user.mb_str()); } return wxConvertMB2WX(who ? who->pw_dir : 0); } // ---------------------------------------------------------------------------- // network and user id routines // ---------------------------------------------------------------------------- // retrieve either the hostname or FQDN depending on platform (caller must // check whether it's one or the other, this is why this function is for // private use only) static bool wxGetHostNameInternal(wxChar *buf, int sz) { wxCHECK_MSG( buf, FALSE, wxT("NULL pointer in wxGetHostNameInternal") ); *buf = wxT('\0'); // we're using uname() which is POSIX instead of less standard sysinfo() #if defined(HAVE_UNAME) struct utsname uts; bool ok = uname(&uts) != -1; if ( ok ) { wxStrncpy(buf, wxConvertMB2WX(uts.nodename), sz - 1); buf[sz] = wxT('\0'); } #elif defined(HAVE_GETHOSTNAME) bool ok = gethostname(buf, sz) != -1; #else // no uname, no gethostname wxFAIL_MSG(wxT("don't know host name for this machine")); bool ok = FALSE; #endif // uname/gethostname if ( !ok ) { wxLogSysError(_("Cannot get the hostname")); } return ok; } bool wxGetHostName(wxChar *buf, int sz) { bool ok = wxGetHostNameInternal(buf, sz); if ( ok ) { // BSD systems return the FQDN, we only want the hostname, so extract // it (we consider that dots are domain separators) wxChar *dot = wxStrchr(buf, wxT('.')); if ( dot ) { // nuke it *dot = wxT('\0'); } } return ok; } bool wxGetFullHostName(wxChar *buf, int sz) { bool ok = wxGetHostNameInternal(buf, sz); if ( ok ) { if ( !wxStrchr(buf, wxT('.')) ) { struct hostent *host = gethostbyname(wxConvertWX2MB(buf)); if ( !host ) { wxLogSysError(_("Cannot get the official hostname")); ok = FALSE; } else { // the canonical name wxStrncpy(buf, wxConvertMB2WX(host->h_name), sz); } } //else: it's already a FQDN (BSD behaves this way) } return ok; } bool wxGetUserId(wxChar *buf, int sz) { struct passwd *who; *buf = wxT('\0'); if ((who = getpwuid(getuid ())) != NULL) { wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1); return TRUE; } return FALSE; } bool wxGetUserName(wxChar *buf, int sz) { struct passwd *who; *buf = wxT('\0'); if ((who = getpwuid (getuid ())) != NULL) { // pw_gecos field in struct passwd is not standard #ifdef HAVE_PW_GECOS char *comma = strchr(who->pw_gecos, ','); if (comma) *comma = '\0'; // cut off non-name comment fields wxStrncpy (buf, wxConvertMB2WX(who->pw_gecos), sz - 1); #else // !HAVE_PW_GECOS wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1); #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS return TRUE; } return FALSE; } wxString wxGetOsDescription() { #ifndef WXWIN_OS_DESCRIPTION #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure #else return WXWIN_OS_DESCRIPTION; #endif } // this function returns the GUI toolkit version in GUI programs, but OS // version in non-GUI ones #if !wxUSE_GUI int wxGetOsVersion(int *majorVsn, int *minorVsn) { int major, minor; char name[256]; if ( sscanf(WXWIN_OS_DESCRIPTION, "%s %d.%d", name, &major, &minor) != 3 ) { // unreckognized uname string format major = minor = -1; } if ( majorVsn ) *majorVsn = major; if ( minorVsn ) *minorVsn = minor; return wxUNIX; } #endif // !wxUSE_GUI long wxGetFreeMemory() { #if defined(__LINUX__) // get it from /proc/meminfo FILE *fp = fopen("/proc/meminfo", "r"); if ( fp ) { long memFree = -1; char buf[1024]; if ( fgets(buf, WXSIZEOF(buf), fp) && fgets(buf, WXSIZEOF(buf), fp) ) { long memTotal, memUsed; sscanf(buf, "Mem: %ld %ld %ld", &memTotal, &memUsed, &memFree); } fclose(fp); return memFree; } #elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES) return sysconf(_SC_AVPHYS_PAGES)*sysconf(_SC_PAGESIZE); //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably #endif // can't find it out return -1; } bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree) { #ifdef HAVE_STATFS struct statfs fs; if ( statfs(path, &fs) != 0 ) { wxLogSysError("Failed to get file system statistics"); return FALSE; } if ( pTotal ) { *pTotal = wxLongLong(fs.f_blocks) * fs.f_bsize; } if ( pFree ) { *pFree = wxLongLong(fs.f_bavail) * fs.f_bsize; } return TRUE; #endif // HAVE_STATFS return FALSE; } // ---------------------------------------------------------------------------- // env vars // ---------------------------------------------------------------------------- bool wxGetEnv(const wxString& var, wxString *value) { // wxGetenv is defined as getenv() wxChar *p = wxGetenv(var); if ( !p ) return FALSE; if ( value ) { *value = p; } return TRUE; } bool wxSetEnv(const wxString& variable, const wxChar *value) { #if defined(HAVE_SETENV) return setenv(variable.mb_str(), value ? wxString(value).mb_str().data() : NULL, 1 /* overwrite */) == 0; #elif defined(HAVE_PUTENV) wxString s = variable; if ( value ) s << _T('=') << value; // transform to ANSI const char *p = s.mb_str(); // the string will be free()d by libc char *buf = (char *)malloc(strlen(p) + 1); strcpy(buf, p); return putenv(buf) == 0; #else // no way to set an env var return FALSE; #endif } // ---------------------------------------------------------------------------- // signal handling // ---------------------------------------------------------------------------- #if wxUSE_ON_FATAL_EXCEPTION #include static void wxFatalSignalHandler(wxTYPE_SA_HANDLER) { if ( wxTheApp ) { // give the user a chance to do something special about this wxTheApp->OnFatalException(); } abort(); } bool wxHandleFatalExceptions(bool doit) { // old sig handlers static bool s_savedHandlers = FALSE; static struct sigaction s_handlerFPE, s_handlerILL, s_handlerBUS, s_handlerSEGV; bool ok = TRUE; if ( doit && !s_savedHandlers ) { // install the signal handler struct sigaction act; // some systems extend it with non std fields, so zero everything memset(&act, 0, sizeof(act)); act.sa_handler = wxFatalSignalHandler; sigemptyset(&act.sa_mask); act.sa_flags = 0; ok &= sigaction(SIGFPE, &act, &s_handlerFPE) == 0; ok &= sigaction(SIGILL, &act, &s_handlerILL) == 0; ok &= sigaction(SIGBUS, &act, &s_handlerBUS) == 0; ok &= sigaction(SIGSEGV, &act, &s_handlerSEGV) == 0; if ( !ok ) { wxLogDebug(_T("Failed to install our signal handler.")); } s_savedHandlers = TRUE; } else if ( s_savedHandlers ) { // uninstall the signal handler ok &= sigaction(SIGFPE, &s_handlerFPE, NULL) == 0; ok &= sigaction(SIGILL, &s_handlerILL, NULL) == 0; ok &= sigaction(SIGBUS, &s_handlerBUS, NULL) == 0; ok &= sigaction(SIGSEGV, &s_handlerSEGV, NULL) == 0; if ( !ok ) { wxLogDebug(_T("Failed to uninstall our signal handler.")); } s_savedHandlers = FALSE; } //else: nothing to do return ok; } #endif // wxUSE_ON_FATAL_EXCEPTION // ---------------------------------------------------------------------------- // error and debug output routines (deprecated, use wxLog) // ---------------------------------------------------------------------------- void wxDebugMsg( const char *format, ... ) { va_list ap; va_start( ap, format ); vfprintf( stderr, format, ap ); fflush( stderr ); va_end(ap); } void wxError( const wxString &msg, const wxString &title ) { wxFprintf( stderr, _("Error ") ); if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) ); if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) ); wxFprintf( stderr, wxT(".\n") ); } void wxFatalError( const wxString &msg, const wxString &title ) { wxFprintf( stderr, _("Error ") ); if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) ); if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) ); wxFprintf( stderr, wxT(".\n") ); exit(3); // the same exit code as for abort() }