1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: generic Unix implementation of many wx functions
4 // Author: Vadim Zeitlin
6 // Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
19 #include "wx/string.h"
26 #include "wx/process.h"
27 #include "wx/thread.h"
29 #include "wx/stream.h"
33 # include <sys/param.h>
34 # include <sys/mount.h>
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
256 long lRc
= wxExecute(argv
, flags
, process
);
261 delete [] argv
[argc
++];
266 // ----------------------------------------------------------------------------
268 // ----------------------------------------------------------------------------
270 static wxString
wxMakeShellCommand(const wxString
& command
)
275 // just an interactive shell
280 // execute command in a shell
281 cmd
<< _T("/bin/sh -c '") << command
<< _T('\'');
287 bool wxShell(const wxString
& command
)
289 return wxExecute(wxMakeShellCommand(command
), wxEXEC_SYNC
) == 0;
292 bool wxShell(const wxString
& command
, wxArrayString
& output
)
294 wxCHECK_MSG( !!command
, FALSE
, _T("can't exec shell non interactively") );
296 return wxExecute(wxMakeShellCommand(command
), output
);
299 // Shutdown or reboot the PC
300 bool wxShutdown(wxShutdownFlags wFlags
)
305 case wxSHUTDOWN_POWEROFF
:
309 case wxSHUTDOWN_REBOOT
:
314 wxFAIL_MSG( _T("unknown wxShutdown() flag") );
318 return system(wxString::Format(_T("init %c"), level
).mb_str()) == 0;
324 void wxHandleProcessTermination(wxEndProcessData
*proc_data
)
326 // notify user about termination if required
327 if ( proc_data
->process
)
329 proc_data
->process
->OnTerminate(proc_data
->pid
, proc_data
->exitcode
);
333 if ( proc_data
->pid
> 0 )
339 // let wxExecute() know that the process has terminated
346 // ----------------------------------------------------------------------------
347 // wxStream classes to support IO redirection in wxExecute
348 // ----------------------------------------------------------------------------
352 class wxProcessFileInputStream
: public wxInputStream
355 wxProcessFileInputStream(int fd
) { m_fd
= fd
; }
356 ~wxProcessFileInputStream() { close(m_fd
); }
358 virtual bool Eof() const;
361 size_t OnSysRead(void *buffer
, size_t bufsize
);
367 class wxProcessFileOutputStream
: public wxOutputStream
370 wxProcessFileOutputStream(int fd
) { m_fd
= fd
; }
371 ~wxProcessFileOutputStream() { close(m_fd
); }
374 size_t OnSysWrite(const void *buffer
, size_t bufsize
);
380 bool wxProcessFileInputStream::Eof() const
382 if ( m_lasterror
== wxSTREAM_EOF
)
385 // check if there is any input available
392 FD_SET(m_fd
, &readfds
);
393 switch ( select(m_fd
+ 1, &readfds
, NULL
, NULL
, &tv
) )
396 wxLogSysError(_("Impossible to get child process input"));
403 wxFAIL_MSG(_T("unexpected select() return value"));
404 // still fall through
407 // input available: check if there is any
408 return wxInputStream::Eof();
412 size_t wxProcessFileInputStream::OnSysRead(void *buffer
, size_t bufsize
)
414 int ret
= read(m_fd
, buffer
, bufsize
);
417 m_lasterror
= wxSTREAM_EOF
;
419 else if ( ret
== -1 )
421 m_lasterror
= wxSTREAM_READ_ERROR
;
426 m_lasterror
= wxSTREAM_NOERROR
;
432 size_t wxProcessFileOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
434 int ret
= write(m_fd
, buffer
, bufsize
);
437 m_lasterror
= wxSTREAM_WRITE_ERROR
;
442 m_lasterror
= wxSTREAM_NOERROR
;
448 // ----------------------------------------------------------------------------
449 // wxStreamTempBuffer
450 // ----------------------------------------------------------------------------
453 Extract of a mail to wx-users to give the context of the problem we are
454 trying to solve here:
456 MC> If I run the command:
457 MC> find . -name "*.h" -exec grep linux {} \;
458 MC> in the exec sample synchronously from the 'Capture command output'
459 MC> menu, wxExecute never returns. I have to xkill it. Has anyone
460 MC> else encountered this?
462 Yes, I can reproduce it too.
464 I even think I understand why it happens: before launching the external
465 command we set up a pipe with a valid file descriptor on the reading side
466 when the output is redirected. So the subprocess happily writes to it ...
467 until the pipe buffer (which is usually quite big on Unix, I think the
468 default is 4Kb) is full. Then the writing process stops and waits until we
469 read some data from the pipe to be able to continue writing to it but we
470 never do it because we wait until it terminates to start reading and so we
471 have a classical deadlock.
473 Here is the fix: we now read the output as soon as it appears into a temp
474 buffer (wxStreamTempBuffer object) and later just stuff it back into the
475 stream when the process terminates. See supporting code in wxExecute()
478 Note that this is horribly inefficient for large amounts of output (count
479 the number of times we copy the data around) and so a better API is badly
483 class wxStreamTempBuffer
486 wxStreamTempBuffer();
488 // call to associate a stream with this buffer, otherwise nothing happens
490 void Init(wxInputStream
*stream
);
492 // check for input on our stream and cache it in our buffer if any
495 ~wxStreamTempBuffer();
498 // the stream we're buffering, if NULL we don't do anything at all
499 wxInputStream
*m_stream
;
501 // the buffer of size m_size (NULL if m_size == 0)
504 // the size of the buffer
508 wxStreamTempBuffer::wxStreamTempBuffer()
515 void wxStreamTempBuffer::Init(wxInputStream
*stream
)
520 void wxStreamTempBuffer::Update()
522 if ( m_stream
&& !m_stream
->Eof() )
524 // realloc in blocks of 4Kb: this is the default (and minimal) buffer
525 // size of the Unix pipes so it should be the optimal step
526 static const size_t incSize
= 4096;
528 void *buf
= realloc(m_buffer
, m_size
+ incSize
);
531 // don't read any more, we don't have enough memory to do it
534 else // got memory for the buffer
537 m_stream
->Read((char *)m_buffer
+ m_size
, incSize
);
538 m_size
+= m_stream
->LastRead();
543 wxStreamTempBuffer::~wxStreamTempBuffer()
547 m_stream
->Ungetch(m_buffer
, m_size
);
552 #endif // wxUSE_STREAMS
554 // ----------------------------------------------------------------------------
555 // wxPipe: this encpasulates pipe() system call
556 // ----------------------------------------------------------------------------
561 // the symbolic names for the pipe ends
573 // default ctor doesn't do anything
574 wxPipe() { m_fds
[Read
] = m_fds
[Write
] = INVALID_FD
; }
576 // create the pipe, return TRUE if ok, FALSE on error
579 if ( pipe(m_fds
) == -1 )
581 wxLogSysError(_("Pipe creation failed"));
589 // return TRUE if we were created successfully
590 bool IsOk() const { return m_fds
[Read
] != INVALID_FD
; }
592 // return the descriptor for one of the pipe ends
593 int operator[](Direction which
) const
595 wxASSERT_MSG( which
>= 0 && (size_t)which
< WXSIZEOF(m_fds
),
596 _T("invalid pipe index") );
601 // detach a descriptor, meaning that the pipe dtor won't close it, and
603 int Detach(Direction which
)
605 wxASSERT_MSG( which
>= 0 && (size_t)which
< WXSIZEOF(m_fds
),
606 _T("invalid pipe index") );
608 int fd
= m_fds
[which
];
609 m_fds
[which
] = INVALID_FD
;
614 // close the pipe descriptors
617 for ( size_t n
= 0; n
< WXSIZEOF(m_fds
); n
++ )
619 if ( m_fds
[n
] != INVALID_FD
)
624 // dtor closes the pipe descriptors
625 ~wxPipe() { Close(); }
631 // ----------------------------------------------------------------------------
632 // wxExecute: the real worker function
633 // ----------------------------------------------------------------------------
635 long wxExecute(wxChar
**argv
,
639 // for the sync execution, we return -1 to indicate failure, but for async
640 // case we return 0 which is never a valid PID
642 // we define this as a macro, not a variable, to avoid compiler warnings
643 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
644 #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)
646 wxCHECK_MSG( *argv
, ERROR_RETURN_CODE
, wxT("can't exec empty command") );
650 char *mb_argv
[WXEXECUTE_NARGS
];
652 while (argv
[mb_argc
])
654 wxWX2MBbuf mb_arg
= wxConvertWX2MB(argv
[mb_argc
]);
655 mb_argv
[mb_argc
] = strdup(mb_arg
);
658 mb_argv
[mb_argc
] = (char *) NULL
;
660 // this macro will free memory we used above
661 #define ARGS_CLEANUP \
662 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
663 free(mb_argv[mb_argc])
665 // no need for cleanup
668 wxChar
**mb_argv
= argv
;
669 #endif // Unicode/ANSI
673 wxPipe pipeEndProcDetect
;
674 if ( !pipeEndProcDetect
.Create() )
676 wxLogError( _("Failed to execute '%s'\n"), *argv
);
680 return ERROR_RETURN_CODE
;
684 // pipes for inter process communication
685 wxPipe pipeIn
, // stdin
689 if ( process
&& process
->IsRedirected() )
691 if ( !pipeIn
.Create() || !pipeOut
.Create() || !pipeErr
.Create() )
693 wxLogError( _("Failed to execute '%s'\n"), *argv
);
697 return ERROR_RETURN_CODE
;
708 if ( pid
== -1 ) // error?
710 wxLogSysError( _("Fork failed") );
714 return ERROR_RETURN_CODE
;
716 else if ( pid
== 0 ) // we're in child
719 // reading side can be safely closed but we should keep the write one
721 pipeEndProcDetect
.Detach(wxPipe::Write
);
724 // These lines close the open file descriptors to to avoid any
725 // input/output which might block the process or irritate the user. If
726 // one wants proper IO for the subprocess, the right thing to do is to
727 // start an xterm executing it.
728 if ( !(flags
& wxEXEC_SYNC
) )
730 for ( int fd
= 0; fd
< FD_SETSIZE
; fd
++ )
732 if ( fd
== pipeIn
[wxPipe::Read
]
733 || fd
== pipeOut
[wxPipe::Write
]
734 || fd
== pipeErr
[wxPipe::Write
]
736 || fd
== pipeEndProcDetect
[wxPipe::Write
]
740 // don't close this one, we still need it
744 // leave stderr opened too, it won't do any harm
745 if ( fd
!= STDERR_FILENO
)
750 if ( flags
& wxEXEC_MAKE_GROUP_LEADER
)
752 // Set process group to child process' pid. Then killing -pid
753 // of the parent will kill the process and all of its children.
759 // redirect stdio, stdout and stderr
762 if ( dup2(pipeIn
[wxPipe::Read
], STDIN_FILENO
) == -1 ||
763 dup2(pipeOut
[wxPipe::Write
], STDOUT_FILENO
) == -1 ||
764 dup2(pipeErr
[wxPipe::Write
], STDERR_FILENO
) == -1 )
766 wxLogSysError(_("Failed to redirect child process input/output"));
774 execvp (*mb_argv
, mb_argv
);
776 // there is no return after successful exec()
779 // some compilers complain about missing return - of course, they
780 // should know that exit() doesn't return but what else can we do if
783 // and, sure enough, other compilers complain about unreachable code
784 // after exit() call, so we can just always have return here...
785 #if defined(__VMS) || defined(__INTEL_COMPILER)
789 else // we're in parent
793 // pipe initialization: construction of the wxStreams
795 wxStreamTempBuffer bufIn
, bufErr
;
796 #endif // wxUSE_STREAMS
798 if ( process
&& process
->IsRedirected() )
801 // in/out for subprocess correspond to our out/in
802 wxOutputStream
*outStream
=
803 new wxProcessFileOutputStream(pipeIn
.Detach(wxPipe::Write
));
805 wxInputStream
*inStream
=
806 new wxProcessFileInputStream(pipeOut
.Detach(wxPipe::Read
));
808 wxInputStream
*errStream
=
809 new wxProcessFileInputStream(pipeErr
.Detach(wxPipe::Read
));
811 process
->SetPipeStreams(inStream
, outStream
, errStream
);
813 bufIn
.Init(inStream
);
814 bufErr
.Init(errStream
);
815 #endif // wxUSE_STREAMS
825 #if wxUSE_GUI && !defined(__WXMICROWIN__)
826 wxEndProcessData
*data
= new wxEndProcessData
;
828 data
->tag
= wxAddProcessCallback
831 pipeEndProcDetect
.Detach(wxPipe::Read
)
834 pipeEndProcDetect
.Close();
836 if ( flags
& wxEXEC_SYNC
)
838 // we may have process for capturing the program output, but it's
839 // not used in wxEndProcessData in the case of sync execution
840 data
->process
= NULL
;
842 // sync execution: indicate it by negating the pid
848 // data->pid will be set to 0 from GTK_EndProcessDetector when the
849 // process terminates
850 while ( data
->pid
!= 0 )
855 #endif // wxUSE_STREAMS
857 // give GTK+ a chance to call GTK_EndProcessDetector here and
858 // also repaint the GUI
862 int exitcode
= data
->exitcode
;
868 else // async execution
870 // async execution, nothing special to do - caller will be
871 // notified about the process termination if process != NULL, data
872 // will be deleted in GTK_EndProcessDetector
873 data
->process
= process
;
880 wxASSERT_MSG( flags
& wxEXEC_SYNC
,
881 wxT("async execution not supported yet") );
884 if ( waitpid(pid
, &exitcode
, 0) == -1 || !WIFEXITED(exitcode
) )
886 wxLogSysError(_("Waiting for subprocess termination failed"));
894 #undef ERROR_RETURN_CODE
897 // ----------------------------------------------------------------------------
898 // file and directory functions
899 // ----------------------------------------------------------------------------
901 const wxChar
* wxGetHomeDir( wxString
*home
)
903 *home
= wxGetUserHome( wxString() );
905 if ( home
->IsEmpty() )
909 if ( tmp
.Last() != wxT(']'))
910 if ( tmp
.Last() != wxT('/')) *home
<< wxT('/');
912 return home
->c_str();
916 const wxMB2WXbuf
wxGetUserHome( const wxString
&user
)
917 #else // just for binary compatibility -- there is no 'const' here
918 char *wxGetUserHome( const wxString
&user
)
921 struct passwd
*who
= (struct passwd
*) NULL
;
927 if ((ptr
= wxGetenv(wxT("HOME"))) != NULL
)
931 if ((ptr
= wxGetenv(wxT("USER"))) != NULL
|| (ptr
= wxGetenv(wxT("LOGNAME"))) != NULL
)
933 who
= getpwnam(wxConvertWX2MB(ptr
));
936 // We now make sure the the user exists!
939 who
= getpwuid(getuid());
944 who
= getpwnam (user
.mb_str());
947 return wxConvertMB2WX(who
? who
->pw_dir
: 0);
950 // ----------------------------------------------------------------------------
951 // network and user id routines
952 // ----------------------------------------------------------------------------
954 // retrieve either the hostname or FQDN depending on platform (caller must
955 // check whether it's one or the other, this is why this function is for
957 static bool wxGetHostNameInternal(wxChar
*buf
, int sz
)
959 wxCHECK_MSG( buf
, FALSE
, wxT("NULL pointer in wxGetHostNameInternal") );
963 // we're using uname() which is POSIX instead of less standard sysinfo()
964 #if defined(HAVE_UNAME)
966 bool ok
= uname(&uts
) != -1;
969 wxStrncpy(buf
, wxConvertMB2WX(uts
.nodename
), sz
- 1);
972 #elif defined(HAVE_GETHOSTNAME)
973 bool ok
= gethostname(buf
, sz
) != -1;
974 #else // no uname, no gethostname
975 wxFAIL_MSG(wxT("don't know host name for this machine"));
978 #endif // uname/gethostname
982 wxLogSysError(_("Cannot get the hostname"));
988 bool wxGetHostName(wxChar
*buf
, int sz
)
990 bool ok
= wxGetHostNameInternal(buf
, sz
);
994 // BSD systems return the FQDN, we only want the hostname, so extract
995 // it (we consider that dots are domain separators)
996 wxChar
*dot
= wxStrchr(buf
, wxT('.'));
1007 bool wxGetFullHostName(wxChar
*buf
, int sz
)
1009 bool ok
= wxGetHostNameInternal(buf
, sz
);
1013 if ( !wxStrchr(buf
, wxT('.')) )
1015 struct hostent
*host
= gethostbyname(wxConvertWX2MB(buf
));
1018 wxLogSysError(_("Cannot get the official hostname"));
1024 // the canonical name
1025 wxStrncpy(buf
, wxConvertMB2WX(host
->h_name
), sz
);
1028 //else: it's already a FQDN (BSD behaves this way)
1034 bool wxGetUserId(wxChar
*buf
, int sz
)
1039 if ((who
= getpwuid(getuid ())) != NULL
)
1041 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz
- 1);
1048 bool wxGetUserName(wxChar
*buf
, int sz
)
1053 if ((who
= getpwuid (getuid ())) != NULL
)
1055 // pw_gecos field in struct passwd is not standard
1056 #ifdef HAVE_PW_GECOS
1057 char *comma
= strchr(who
->pw_gecos
, ',');
1059 *comma
= '\0'; // cut off non-name comment fields
1060 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_gecos
), sz
- 1);
1061 #else // !HAVE_PW_GECOS
1062 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz
- 1);
1063 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
1071 wxString
wxGetOsDescription()
1073 #ifndef WXWIN_OS_DESCRIPTION
1074 #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
1076 return WXWIN_OS_DESCRIPTION
;
1081 // this function returns the GUI toolkit version in GUI programs, but OS
1082 // version in non-GUI ones
1085 int wxGetOsVersion(int *majorVsn
, int *minorVsn
)
1090 if ( sscanf(WXWIN_OS_DESCRIPTION
, "%s %d.%d", name
, &major
, &minor
) != 3 )
1092 // unreckognized uname string format
1104 #endif // !wxUSE_GUI
1106 unsigned long wxGetProcessId()
1108 return (unsigned long)getpid();
1111 long wxGetFreeMemory()
1113 #if defined(__LINUX__)
1114 // get it from /proc/meminfo
1115 FILE *fp
= fopen("/proc/meminfo", "r");
1121 if ( fgets(buf
, WXSIZEOF(buf
), fp
) && fgets(buf
, WXSIZEOF(buf
), fp
) )
1123 long memTotal
, memUsed
;
1124 sscanf(buf
, "Mem: %ld %ld %ld", &memTotal
, &memUsed
, &memFree
);
1131 #elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES)
1132 return sysconf(_SC_AVPHYS_PAGES
)*sysconf(_SC_PAGESIZE
);
1133 //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1136 // can't find it out
1140 bool wxGetDiskSpace(const wxString
& path
, wxLongLong
*pTotal
, wxLongLong
*pFree
)
1142 #if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
1143 // the case to "char *" is needed for AIX 4.3
1145 if ( statfs((char *)path
.fn_str(), &fs
) != 0 )
1147 wxLogSysError("Failed to get file system statistics");
1152 // under Solaris we also have to use f_frsize field instead of f_bsize
1153 // which is in general a multiple of f_frsize
1155 wxLongLong blockSize
= fs
.f_frsize
;
1156 #else // HAVE_STATFS
1157 wxLongLong blockSize
= fs
.f_bsize
;
1158 #endif // HAVE_STATVFS/HAVE_STATFS
1162 *pTotal
= wxLongLong(fs
.f_blocks
) * blockSize
;
1167 *pFree
= wxLongLong(fs
.f_bavail
) * blockSize
;
1171 #else // !HAVE_STATFS && !HAVE_STATVFS
1173 #endif // HAVE_STATFS
1176 // ----------------------------------------------------------------------------
1178 // ----------------------------------------------------------------------------
1180 bool wxGetEnv(const wxString
& var
, wxString
*value
)
1182 // wxGetenv is defined as getenv()
1183 wxChar
*p
= wxGetenv(var
);
1195 bool wxSetEnv(const wxString
& variable
, const wxChar
*value
)
1197 #if defined(HAVE_SETENV)
1198 return setenv(variable
.mb_str(),
1199 value
? (const char *)wxString(value
).mb_str()
1201 1 /* overwrite */) == 0;
1202 #elif defined(HAVE_PUTENV)
1203 wxString s
= variable
;
1205 s
<< _T('=') << value
;
1207 // transform to ANSI
1208 const char *p
= s
.mb_str();
1210 // the string will be free()d by libc
1211 char *buf
= (char *)malloc(strlen(p
) + 1);
1214 return putenv(buf
) == 0;
1215 #else // no way to set an env var
1220 // ----------------------------------------------------------------------------
1222 // ----------------------------------------------------------------------------
1224 #if wxUSE_ON_FATAL_EXCEPTION
1228 extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER
)
1232 // give the user a chance to do something special about this
1233 wxTheApp
->OnFatalException();
1239 bool wxHandleFatalExceptions(bool doit
)
1242 static bool s_savedHandlers
= FALSE
;
1243 static struct sigaction s_handlerFPE
,
1249 if ( doit
&& !s_savedHandlers
)
1251 // install the signal handler
1252 struct sigaction act
;
1254 // some systems extend it with non std fields, so zero everything
1255 memset(&act
, 0, sizeof(act
));
1257 act
.sa_handler
= wxFatalSignalHandler
;
1258 sigemptyset(&act
.sa_mask
);
1261 ok
&= sigaction(SIGFPE
, &act
, &s_handlerFPE
) == 0;
1262 ok
&= sigaction(SIGILL
, &act
, &s_handlerILL
) == 0;
1263 ok
&= sigaction(SIGBUS
, &act
, &s_handlerBUS
) == 0;
1264 ok
&= sigaction(SIGSEGV
, &act
, &s_handlerSEGV
) == 0;
1267 wxLogDebug(_T("Failed to install our signal handler."));
1270 s_savedHandlers
= TRUE
;
1272 else if ( s_savedHandlers
)
1274 // uninstall the signal handler
1275 ok
&= sigaction(SIGFPE
, &s_handlerFPE
, NULL
) == 0;
1276 ok
&= sigaction(SIGILL
, &s_handlerILL
, NULL
) == 0;
1277 ok
&= sigaction(SIGBUS
, &s_handlerBUS
, NULL
) == 0;
1278 ok
&= sigaction(SIGSEGV
, &s_handlerSEGV
, NULL
) == 0;
1281 wxLogDebug(_T("Failed to uninstall our signal handler."));
1284 s_savedHandlers
= FALSE
;
1286 //else: nothing to do
1291 #endif // wxUSE_ON_FATAL_EXCEPTION
1293 // ----------------------------------------------------------------------------
1294 // error and debug output routines (deprecated, use wxLog)
1295 // ----------------------------------------------------------------------------
1297 #if WXWIN_COMPATIBILITY_2_2
1299 void wxDebugMsg( const char *format
, ... )
1302 va_start( ap
, format
);
1303 vfprintf( stderr
, format
, ap
);
1308 void wxError( const wxString
&msg
, const wxString
&title
)
1310 wxFprintf( stderr
, _("Error ") );
1311 if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) );
1312 if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) );
1313 wxFprintf( stderr
, wxT(".\n") );
1316 void wxFatalError( const wxString
&msg
, const wxString
&title
)
1318 wxFprintf( stderr
, _("Error ") );
1319 if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) );
1320 if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) );
1321 wxFprintf( stderr
, wxT(".\n") );
1322 exit(3); // the same exit code as for abort()
1325 #endif // WXWIN_COMPATIBILITY_2_2