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/wfstream.h"
33 # include <sys/param.h>
34 # include <sys/mount.h>
40 // not only the statfs syscall is called differently depending on platform, but
41 // we also can't use "struct statvfs" under Solaris because it breaks down if
42 // HAVE_LARGEFILE_SUPPORT == 1 and we must use statvfs_t instead
44 #include <sys/statvfs.h>
46 #define statfs statvfs
47 #define wxStatFs statvfs_t
49 #define wxStatFs struct statfs
50 #endif // HAVE_STAT[V]FS
53 #include "wx/unix/execute.h"
56 // SGI signal.h defines signal handler arguments differently depending on
57 // whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it
58 #if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS)
59 #define _LANGUAGE_C_PLUS_PLUS 1
66 #include <sys/types.h>
73 #include <fcntl.h> // for O_WRONLY and friends
74 #include <time.h> // nanosleep() and/or usleep()
75 #include <ctype.h> // isspace()
76 #include <sys/time.h> // needed for FD_SETSIZE
79 #include <sys/utsname.h> // for uname()
82 // ----------------------------------------------------------------------------
83 // conditional compilation
84 // ----------------------------------------------------------------------------
86 // many versions of Unices have this function, but it is not defined in system
87 // headers - please add your system here if it is the case for your OS.
88 // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
89 #if !defined(HAVE_USLEEP) && \
90 (defined(__SUN__) && !defined(__SunOs_5_6) && \
91 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
92 defined(__osf__) || defined(__EMX__)
96 int usleep(unsigned int usec
);
99 /* I copied this from the XFree86 diffs. AV. */
100 #define INCL_DOSPROCESS
102 inline void usleep(unsigned long delay
)
104 DosSleep(delay
? (delay
/1000l) : 1l);
106 #else // !Sun && !EMX
107 void usleep(unsigned long usec
);
109 #endif // Sun/EMX/Something else
112 #define HAVE_USLEEP 1
113 #endif // Unices without usleep()
115 // ============================================================================
117 // ============================================================================
119 // ----------------------------------------------------------------------------
121 // ----------------------------------------------------------------------------
123 void wxSleep(int nSecs
)
128 void wxUsleep(unsigned long milliseconds
)
130 #if defined(HAVE_NANOSLEEP)
132 tmReq
.tv_sec
= (time_t)(milliseconds
/ 1000);
133 tmReq
.tv_nsec
= (milliseconds
% 1000) * 1000 * 1000;
135 // we're not interested in remaining time nor in return value
136 (void)nanosleep(&tmReq
, (timespec
*)NULL
);
137 #elif defined(HAVE_USLEEP)
138 // uncomment this if you feel brave or if you are sure that your version
139 // of Solaris has a safe usleep() function but please notice that usleep()
140 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
141 // documented as MT-Safe
142 #if defined(__SUN__) && wxUSE_THREADS
143 #error "usleep() cannot be used in MT programs under Solaris."
146 usleep(milliseconds
* 1000); // usleep(3) wants microseconds
147 #elif defined(HAVE_SLEEP)
148 // under BeOS sleep() takes seconds (what about other platforms, if any?)
149 sleep(milliseconds
* 1000);
150 #else // !sleep function
151 #error "usleep() or nanosleep() function required for wxUsleep"
152 #endif // sleep function
155 // ----------------------------------------------------------------------------
156 // process management
157 // ----------------------------------------------------------------------------
159 int wxKill(long pid
, wxSignal sig
, wxKillError
*rc
)
161 int err
= kill((pid_t
)pid
, (int)sig
);
171 *rc
= wxKILL_BAD_SIGNAL
;
175 *rc
= wxKILL_ACCESS_DENIED
;
179 *rc
= wxKILL_NO_PROCESS
;
183 // this goes against Unix98 docs so log it
184 wxLogDebug(_T("unexpected kill(2) return value %d"), err
);
194 #define WXEXECUTE_NARGS 127
196 long wxExecute( const wxString
& command
, int flags
, wxProcess
*process
)
198 wxCHECK_MSG( !command
.IsEmpty(), 0, wxT("can't exec empty command") );
201 wxChar
*argv
[WXEXECUTE_NARGS
];
203 const wxChar
*cptr
= command
.c_str();
204 wxChar quotechar
= wxT('\0'); // is arg quoted?
205 bool escaped
= FALSE
;
207 // split the command line in arguments
211 quotechar
= wxT('\0');
213 // eat leading whitespace:
214 while ( wxIsspace(*cptr
) )
217 if ( *cptr
== wxT('\'') || *cptr
== wxT('"') )
222 if ( *cptr
== wxT('\\') && ! escaped
)
229 // all other characters:
233 // have we reached the end of the argument?
234 if ( (*cptr
== quotechar
&& ! escaped
)
235 || (quotechar
== wxT('\0') && wxIsspace(*cptr
))
236 || *cptr
== wxT('\0') )
238 wxASSERT_MSG( argc
< WXEXECUTE_NARGS
,
239 wxT("too many arguments in wxExecute") );
241 argv
[argc
] = new wxChar
[argument
.length() + 1];
242 wxStrcpy(argv
[argc
], argument
.c_str());
245 // if not at end of buffer, swallow last character:
249 break; // done with this one, start over
255 // do execute the command
259 long lRc
= wxExecute(argv
, flags
, process
);
265 delete [] argv
[argc
++];
270 // ----------------------------------------------------------------------------
272 // ----------------------------------------------------------------------------
274 static wxString
wxMakeShellCommand(const wxString
& command
)
279 // just an interactive shell
284 // execute command in a shell
285 cmd
<< _T("/bin/sh -c '") << command
<< _T('\'');
291 bool wxShell(const wxString
& command
)
293 return wxExecute(wxMakeShellCommand(command
), wxEXEC_SYNC
) == 0;
296 bool wxShell(const wxString
& command
, wxArrayString
& output
)
298 wxCHECK_MSG( !!command
, FALSE
, _T("can't exec shell non interactively") );
300 return wxExecute(wxMakeShellCommand(command
), output
);
303 // Shutdown or reboot the PC
304 bool wxShutdown(wxShutdownFlags wFlags
)
309 case wxSHUTDOWN_POWEROFF
:
313 case wxSHUTDOWN_REBOOT
:
318 wxFAIL_MSG( _T("unknown wxShutdown() flag") );
322 return system(wxString::Format(_T("init %c"), level
).mb_str()) == 0;
328 void wxHandleProcessTermination(wxEndProcessData
*proc_data
)
330 // notify user about termination if required
331 if ( proc_data
->process
)
333 proc_data
->process
->OnTerminate(proc_data
->pid
, proc_data
->exitcode
);
337 if ( proc_data
->pid
> 0 )
343 // let wxExecute() know that the process has terminated
350 // ----------------------------------------------------------------------------
351 // wxStream classes to support IO redirection in wxExecute
352 // ----------------------------------------------------------------------------
356 // ----------------------------------------------------------------------------
357 // wxProcessFileInputStream: stream for reading from a pipe
358 // ----------------------------------------------------------------------------
360 class wxProcessFileInputStream
: public wxFileInputStream
363 wxProcessFileInputStream(int fd
) : wxFileInputStream(fd
) { }
365 // return TRUE if we have anything to read, don't block
366 bool IsAvailable() const;
369 bool wxProcessFileInputStream::IsAvailable() const
371 if ( m_lasterror
== wxSTREAM_EOF
)
374 // check if there is any input available
379 const int fd
= m_file
->fd();
383 FD_SET(fd
, &readfds
);
384 switch ( select(fd
+ 1, &readfds
, NULL
, NULL
, &tv
) )
387 wxLogSysError(_("Impossible to get child process input"));
394 wxFAIL_MSG(_T("unexpected select() return value"));
395 // still fall through
403 // ----------------------------------------------------------------------------
404 // wxStreamTempInputBuffer
405 // ----------------------------------------------------------------------------
408 Extract of a mail to wx-users to give the context of the problem we are
409 trying to solve here:
411 MC> If I run the command:
412 MC> find . -name "*.h" -exec grep linux {} \;
413 MC> in the exec sample synchronously from the 'Capture command output'
414 MC> menu, wxExecute never returns. I have to xkill it. Has anyone
415 MC> else encountered this?
417 Yes, I can reproduce it too.
419 I even think I understand why it happens: before launching the external
420 command we set up a pipe with a valid file descriptor on the reading side
421 when the output is redirected. So the subprocess happily writes to it ...
422 until the pipe buffer (which is usually quite big on Unix, I think the
423 default is 4Kb) is full. Then the writing process stops and waits until we
424 read some data from the pipe to be able to continue writing to it but we
425 never do it because we wait until it terminates to start reading and so we
426 have a classical deadlock.
428 Here is the fix: we now read the output as soon as it appears into a temp
429 buffer (wxStreamTempInputBuffer object) and later just stuff it back into the
430 stream when the process terminates. See supporting code in wxExecute()
433 Note that this is horribly inefficient for large amounts of output (count
434 the number of times we copy the data around) and so a better API is badly
438 class wxStreamTempInputBuffer
441 wxStreamTempInputBuffer();
443 // call to associate a stream with this buffer, otherwise nothing happens
445 void Init(wxProcessFileInputStream
*stream
);
447 // check for input on our stream and cache it in our buffer if any
450 ~wxStreamTempInputBuffer();
453 // the stream we're buffering, if NULL we don't do anything at all
454 wxProcessFileInputStream
*m_stream
;
456 // the buffer of size m_size (NULL if m_size == 0)
459 // the size of the buffer
463 wxStreamTempInputBuffer::wxStreamTempInputBuffer()
470 void wxStreamTempInputBuffer::Init(wxProcessFileInputStream
*stream
)
475 void wxStreamTempInputBuffer::Update()
477 if ( m_stream
&& m_stream
->IsAvailable() )
479 // realloc in blocks of 4Kb: this is the default (and minimal) buffer
480 // size of the Unix pipes so it should be the optimal step
481 static const size_t incSize
= 4096;
483 void *buf
= realloc(m_buffer
, m_size
+ incSize
);
486 // don't read any more, we don't have enough memory to do it
489 else // got memory for the buffer
492 m_stream
->Read((char *)m_buffer
+ m_size
, incSize
);
493 m_size
+= m_stream
->LastRead();
498 wxStreamTempInputBuffer::~wxStreamTempInputBuffer()
502 m_stream
->Ungetch(m_buffer
, m_size
);
507 #endif // wxUSE_STREAMS
509 // ----------------------------------------------------------------------------
510 // wxPipe: this encapsulates pipe() system call
511 // ----------------------------------------------------------------------------
516 // the symbolic names for the pipe ends
528 // default ctor doesn't do anything
529 wxPipe() { m_fds
[Read
] = m_fds
[Write
] = INVALID_FD
; }
531 // create the pipe, return TRUE if ok, FALSE on error
534 if ( pipe(m_fds
) == -1 )
536 wxLogSysError(_("Pipe creation failed"));
544 // return TRUE if we were created successfully
545 bool IsOk() const { return m_fds
[Read
] != INVALID_FD
; }
547 // return the descriptor for one of the pipe ends
548 int operator[](Direction which
) const
550 wxASSERT_MSG( which
>= 0 && (size_t)which
< WXSIZEOF(m_fds
),
551 _T("invalid pipe index") );
556 // detach a descriptor, meaning that the pipe dtor won't close it, and
558 int Detach(Direction which
)
560 wxASSERT_MSG( which
>= 0 && (size_t)which
< WXSIZEOF(m_fds
),
561 _T("invalid pipe index") );
563 int fd
= m_fds
[which
];
564 m_fds
[which
] = INVALID_FD
;
569 // close the pipe descriptors
572 for ( size_t n
= 0; n
< WXSIZEOF(m_fds
); n
++ )
574 if ( m_fds
[n
] != INVALID_FD
)
579 // dtor closes the pipe descriptors
580 ~wxPipe() { Close(); }
586 // ----------------------------------------------------------------------------
587 // wxExecute: the real worker function
588 // ----------------------------------------------------------------------------
590 #pragma message disable codeunreachable
593 long wxExecute(wxChar
**argv
,
597 // for the sync execution, we return -1 to indicate failure, but for async
598 // case we return 0 which is never a valid PID
600 // we define this as a macro, not a variable, to avoid compiler warnings
601 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
602 #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)
604 wxCHECK_MSG( *argv
, ERROR_RETURN_CODE
, wxT("can't exec empty command") );
608 char *mb_argv
[WXEXECUTE_NARGS
];
610 while (argv
[mb_argc
])
612 wxWX2MBbuf mb_arg
= wxConvertWX2MB(argv
[mb_argc
]);
613 mb_argv
[mb_argc
] = strdup(mb_arg
);
616 mb_argv
[mb_argc
] = (char *) NULL
;
618 // this macro will free memory we used above
619 #define ARGS_CLEANUP \
620 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
621 free(mb_argv[mb_argc])
623 // no need for cleanup
626 wxChar
**mb_argv
= argv
;
627 #endif // Unicode/ANSI
631 wxPipe pipeEndProcDetect
;
632 if ( !pipeEndProcDetect
.Create() )
634 wxLogError( _("Failed to execute '%s'\n"), *argv
);
638 return ERROR_RETURN_CODE
;
642 // pipes for inter process communication
643 wxPipe pipeIn
, // stdin
647 if ( process
&& process
->IsRedirected() )
649 if ( !pipeIn
.Create() || !pipeOut
.Create() || !pipeErr
.Create() )
651 wxLogError( _("Failed to execute '%s'\n"), *argv
);
655 return ERROR_RETURN_CODE
;
666 if ( pid
== -1 ) // error?
668 wxLogSysError( _("Fork failed") );
672 return ERROR_RETURN_CODE
;
674 else if ( pid
== 0 ) // we're in child
676 // These lines close the open file descriptors to to avoid any
677 // input/output which might block the process or irritate the user. If
678 // one wants proper IO for the subprocess, the right thing to do is to
679 // start an xterm executing it.
680 if ( !(flags
& wxEXEC_SYNC
) )
682 for ( int fd
= 0; fd
< FD_SETSIZE
; fd
++ )
684 if ( fd
== pipeIn
[wxPipe::Read
]
685 || fd
== pipeOut
[wxPipe::Write
]
686 || fd
== pipeErr
[wxPipe::Write
]
688 || fd
== pipeEndProcDetect
[wxPipe::Write
]
692 // don't close this one, we still need it
696 // leave stderr opened too, it won't do any harm
697 if ( fd
!= STDERR_FILENO
)
703 if ( flags
& wxEXEC_MAKE_GROUP_LEADER
)
705 // Set process group to child process' pid. Then killing -pid
706 // of the parent will kill the process and all of its children.
712 // reading side can be safely closed but we should keep the write one
714 pipeEndProcDetect
.Detach(wxPipe::Write
);
715 pipeEndProcDetect
.Close();
718 // redirect stdin, stdout and stderr
721 if ( dup2(pipeIn
[wxPipe::Read
], STDIN_FILENO
) == -1 ||
722 dup2(pipeOut
[wxPipe::Write
], STDOUT_FILENO
) == -1 ||
723 dup2(pipeErr
[wxPipe::Write
], STDERR_FILENO
) == -1 )
725 wxLogSysError(_("Failed to redirect child process input/output"));
733 execvp (*mb_argv
, mb_argv
);
735 // there is no return after successful exec()
738 // some compilers complain about missing return - of course, they
739 // should know that exit() doesn't return but what else can we do if
742 // and, sure enough, other compilers complain about unreachable code
743 // after exit() call, so we can just always have return here...
744 #if defined(__VMS) || defined(__INTEL_COMPILER)
748 else // we're in parent
752 // prepare for IO redirection
755 // the input buffer bufOut is connected to stdout, this is why it is
756 // called bufOut and not bufIn
757 wxStreamTempInputBuffer bufOut
,
759 #endif // wxUSE_STREAMS
761 if ( process
&& process
->IsRedirected() )
764 wxOutputStream
*inStream
=
765 new wxFileOutputStream(pipeIn
.Detach(wxPipe::Write
));
767 wxProcessFileInputStream
*outStream
=
768 new wxProcessFileInputStream(pipeOut
.Detach(wxPipe::Read
));
770 wxProcessFileInputStream
*errStream
=
771 new wxProcessFileInputStream(pipeErr
.Detach(wxPipe::Read
));
773 process
->SetPipeStreams(outStream
, inStream
, errStream
);
775 bufOut
.Init(outStream
);
776 bufErr
.Init(errStream
);
777 #endif // wxUSE_STREAMS
787 #if wxUSE_GUI && !defined(__WXMICROWIN__)
788 wxEndProcessData
*data
= new wxEndProcessData
;
790 data
->tag
= wxAddProcessCallback
793 pipeEndProcDetect
.Detach(wxPipe::Read
)
796 pipeEndProcDetect
.Close();
798 if ( flags
& wxEXEC_SYNC
)
800 // we may have process for capturing the program output, but it's
801 // not used in wxEndProcessData in the case of sync execution
802 data
->process
= NULL
;
804 // sync execution: indicate it by negating the pid
810 // data->pid will be set to 0 from GTK_EndProcessDetector when the
811 // process terminates
812 while ( data
->pid
!= 0 )
817 #endif // wxUSE_STREAMS
819 // give GTK+ a chance to call GTK_EndProcessDetector here and
820 // also repaint the GUI
824 int exitcode
= data
->exitcode
;
830 else // async execution
832 // async execution, nothing special to do - caller will be
833 // notified about the process termination if process != NULL, data
834 // will be deleted in GTK_EndProcessDetector
835 data
->process
= process
;
842 wxASSERT_MSG( flags
& wxEXEC_SYNC
,
843 wxT("async execution not supported yet") );
846 if ( waitpid(pid
, &exitcode
, 0) == -1 || !WIFEXITED(exitcode
) )
848 wxLogSysError(_("Waiting for subprocess termination failed"));
855 return ERROR_RETURN_CODE
;
858 #pragma message enable codeunreachable
861 #undef ERROR_RETURN_CODE
864 // ----------------------------------------------------------------------------
865 // file and directory functions
866 // ----------------------------------------------------------------------------
868 const wxChar
* wxGetHomeDir( wxString
*home
)
870 *home
= wxGetUserHome( wxString() );
872 if ( home
->IsEmpty() )
876 if ( tmp
.Last() != wxT(']'))
877 if ( tmp
.Last() != wxT('/')) *home
<< wxT('/');
879 return home
->c_str();
883 const wxMB2WXbuf
wxGetUserHome( const wxString
&user
)
884 #else // just for binary compatibility -- there is no 'const' here
885 char *wxGetUserHome( const wxString
&user
)
888 struct passwd
*who
= (struct passwd
*) NULL
;
894 if ((ptr
= wxGetenv(wxT("HOME"))) != NULL
)
898 if ((ptr
= wxGetenv(wxT("USER"))) != NULL
|| (ptr
= wxGetenv(wxT("LOGNAME"))) != NULL
)
900 who
= getpwnam(wxConvertWX2MB(ptr
));
903 // We now make sure the the user exists!
906 who
= getpwuid(getuid());
911 who
= getpwnam (user
.mb_str());
914 return wxConvertMB2WX(who
? who
->pw_dir
: 0);
917 // ----------------------------------------------------------------------------
918 // network and user id routines
919 // ----------------------------------------------------------------------------
921 // retrieve either the hostname or FQDN depending on platform (caller must
922 // check whether it's one or the other, this is why this function is for
924 static bool wxGetHostNameInternal(wxChar
*buf
, int sz
)
926 wxCHECK_MSG( buf
, FALSE
, wxT("NULL pointer in wxGetHostNameInternal") );
930 // we're using uname() which is POSIX instead of less standard sysinfo()
931 #if defined(HAVE_UNAME)
933 bool ok
= uname(&uts
) != -1;
936 wxStrncpy(buf
, wxConvertMB2WX(uts
.nodename
), sz
- 1);
939 #elif defined(HAVE_GETHOSTNAME)
940 bool ok
= gethostname(buf
, sz
) != -1;
941 #else // no uname, no gethostname
942 wxFAIL_MSG(wxT("don't know host name for this machine"));
945 #endif // uname/gethostname
949 wxLogSysError(_("Cannot get the hostname"));
955 bool wxGetHostName(wxChar
*buf
, int sz
)
957 bool ok
= wxGetHostNameInternal(buf
, sz
);
961 // BSD systems return the FQDN, we only want the hostname, so extract
962 // it (we consider that dots are domain separators)
963 wxChar
*dot
= wxStrchr(buf
, wxT('.'));
974 bool wxGetFullHostName(wxChar
*buf
, int sz
)
976 bool ok
= wxGetHostNameInternal(buf
, sz
);
980 if ( !wxStrchr(buf
, wxT('.')) )
982 struct hostent
*host
= gethostbyname(wxConvertWX2MB(buf
));
985 wxLogSysError(_("Cannot get the official hostname"));
991 // the canonical name
992 wxStrncpy(buf
, wxConvertMB2WX(host
->h_name
), sz
);
995 //else: it's already a FQDN (BSD behaves this way)
1001 bool wxGetUserId(wxChar
*buf
, int sz
)
1006 if ((who
= getpwuid(getuid ())) != NULL
)
1008 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz
- 1);
1015 bool wxGetUserName(wxChar
*buf
, int sz
)
1020 if ((who
= getpwuid (getuid ())) != NULL
)
1022 // pw_gecos field in struct passwd is not standard
1023 #ifdef HAVE_PW_GECOS
1024 char *comma
= strchr(who
->pw_gecos
, ',');
1026 *comma
= '\0'; // cut off non-name comment fields
1027 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_gecos
), sz
- 1);
1028 #else // !HAVE_PW_GECOS
1029 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz
- 1);
1030 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
1038 wxString
wxGetOsDescription()
1040 #ifndef WXWIN_OS_DESCRIPTION
1041 #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
1043 return WXWIN_OS_DESCRIPTION
;
1048 // this function returns the GUI toolkit version in GUI programs, but OS
1049 // version in non-GUI ones
1052 int wxGetOsVersion(int *majorVsn
, int *minorVsn
)
1057 if ( sscanf(WXWIN_OS_DESCRIPTION
, "%s %d.%d", name
, &major
, &minor
) != 3 )
1059 // unreckognized uname string format
1071 #endif // !wxUSE_GUI
1073 unsigned long wxGetProcessId()
1075 return (unsigned long)getpid();
1078 long wxGetFreeMemory()
1080 #if defined(__LINUX__)
1081 // get it from /proc/meminfo
1082 FILE *fp
= fopen("/proc/meminfo", "r");
1088 if ( fgets(buf
, WXSIZEOF(buf
), fp
) && fgets(buf
, WXSIZEOF(buf
), fp
) )
1090 long memTotal
, memUsed
;
1091 sscanf(buf
, "Mem: %ld %ld %ld", &memTotal
, &memUsed
, &memFree
);
1098 #elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES)
1099 return sysconf(_SC_AVPHYS_PAGES
)*sysconf(_SC_PAGESIZE
);
1100 //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1103 // can't find it out
1107 bool wxGetDiskSpace(const wxString
& path
, wxLongLong
*pTotal
, wxLongLong
*pFree
)
1109 #if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
1110 // the case to "char *" is needed for AIX 4.3
1112 if ( statfs((char *)(const char*)path
.fn_str(), &fs
) != 0 )
1114 wxLogSysError( wxT("Failed to get file system statistics") );
1119 // under Solaris we also have to use f_frsize field instead of f_bsize
1120 // which is in general a multiple of f_frsize
1122 wxLongLong blockSize
= fs
.f_frsize
;
1123 #else // HAVE_STATFS
1124 wxLongLong blockSize
= fs
.f_bsize
;
1125 #endif // HAVE_STATVFS/HAVE_STATFS
1129 *pTotal
= wxLongLong(fs
.f_blocks
) * blockSize
;
1134 *pFree
= wxLongLong(fs
.f_bavail
) * blockSize
;
1138 #else // !HAVE_STATFS && !HAVE_STATVFS
1140 #endif // HAVE_STATFS
1143 // ----------------------------------------------------------------------------
1145 // ----------------------------------------------------------------------------
1147 bool wxGetEnv(const wxString
& var
, wxString
*value
)
1149 // wxGetenv is defined as getenv()
1150 wxChar
*p
= wxGetenv(var
);
1162 bool wxSetEnv(const wxString
& variable
, const wxChar
*value
)
1164 #if defined(HAVE_SETENV)
1165 return setenv(variable
.mb_str(),
1166 value
? (const char *)wxString(value
).mb_str()
1168 1 /* overwrite */) == 0;
1169 #elif defined(HAVE_PUTENV)
1170 wxString s
= variable
;
1172 s
<< _T('=') << value
;
1174 // transform to ANSI
1175 const char *p
= s
.mb_str();
1177 // the string will be free()d by libc
1178 char *buf
= (char *)malloc(strlen(p
) + 1);
1181 return putenv(buf
) == 0;
1182 #else // no way to set an env var
1187 // ----------------------------------------------------------------------------
1189 // ----------------------------------------------------------------------------
1191 #if wxUSE_ON_FATAL_EXCEPTION
1195 extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER
)
1199 // give the user a chance to do something special about this
1200 wxTheApp
->OnFatalException();
1206 bool wxHandleFatalExceptions(bool doit
)
1209 static bool s_savedHandlers
= FALSE
;
1210 static struct sigaction s_handlerFPE
,
1216 if ( doit
&& !s_savedHandlers
)
1218 // install the signal handler
1219 struct sigaction act
;
1221 // some systems extend it with non std fields, so zero everything
1222 memset(&act
, 0, sizeof(act
));
1224 act
.sa_handler
= wxFatalSignalHandler
;
1225 sigemptyset(&act
.sa_mask
);
1228 ok
&= sigaction(SIGFPE
, &act
, &s_handlerFPE
) == 0;
1229 ok
&= sigaction(SIGILL
, &act
, &s_handlerILL
) == 0;
1230 ok
&= sigaction(SIGBUS
, &act
, &s_handlerBUS
) == 0;
1231 ok
&= sigaction(SIGSEGV
, &act
, &s_handlerSEGV
) == 0;
1234 wxLogDebug(_T("Failed to install our signal handler."));
1237 s_savedHandlers
= TRUE
;
1239 else if ( s_savedHandlers
)
1241 // uninstall the signal handler
1242 ok
&= sigaction(SIGFPE
, &s_handlerFPE
, NULL
) == 0;
1243 ok
&= sigaction(SIGILL
, &s_handlerILL
, NULL
) == 0;
1244 ok
&= sigaction(SIGBUS
, &s_handlerBUS
, NULL
) == 0;
1245 ok
&= sigaction(SIGSEGV
, &s_handlerSEGV
, NULL
) == 0;
1248 wxLogDebug(_T("Failed to uninstall our signal handler."));
1251 s_savedHandlers
= FALSE
;
1253 //else: nothing to do
1258 #endif // wxUSE_ON_FATAL_EXCEPTION
1260 // ----------------------------------------------------------------------------
1261 // error and debug output routines (deprecated, use wxLog)
1262 // ----------------------------------------------------------------------------
1264 #if WXWIN_COMPATIBILITY_2_2
1266 void wxDebugMsg( const char *format
, ... )
1269 va_start( ap
, format
);
1270 vfprintf( stderr
, format
, ap
);
1275 void wxError( const wxString
&msg
, const wxString
&title
)
1277 wxFprintf( stderr
, _("Error ") );
1278 if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) );
1279 if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) );
1280 wxFprintf( stderr
, wxT(".\n") );
1283 void wxFatalError( const wxString
&msg
, const wxString
&title
)
1285 wxFprintf( stderr
, _("Error ") );
1286 if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) );
1287 if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) );
1288 wxFprintf( stderr
, wxT(".\n") );
1289 exit(3); // the same exit code as for abort()
1292 #endif // WXWIN_COMPATIBILITY_2_2