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> 
  41     #include <sys/statvfs.h> 
  43     #define statfs statvfs 
  44 #endif // HAVE_STATVFS 
  47     #include "wx/unix/execute.h" 
  50 // SGI signal.h defines signal handler arguments differently depending on 
  51 // whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it 
  52 #if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS) 
  53     #define _LANGUAGE_C_PLUS_PLUS 1 
  60 #include <sys/types.h> 
  67 #include <fcntl.h>          // for O_WRONLY and friends 
  68 #include <time.h>           // nanosleep() and/or usleep() 
  69 #include <ctype.h>          // isspace() 
  70 #include <sys/time.h>       // needed for FD_SETSIZE 
  73     #include <sys/utsname.h> // for uname() 
  76 // ---------------------------------------------------------------------------- 
  77 // conditional compilation 
  78 // ---------------------------------------------------------------------------- 
  80 // many versions of Unices have this function, but it is not defined in system 
  81 // headers - please add your system here if it is the case for your OS. 
  82 // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this. 
  83 #if !defined(HAVE_USLEEP) && \ 
  84     (defined(__SUN__) && !defined(__SunOs_5_6) && \ 
  85                          !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \ 
  86      defined(__osf__) || defined(__EMX__) 
  90             int usleep(unsigned int usec
); 
  93                 /* I copied this from the XFree86 diffs. AV. */ 
  94                 #define INCL_DOSPROCESS 
  96                 inline void usleep(unsigned long delay
) 
  98                     DosSleep(delay 
? (delay
/1000l) : 1l); 
 100             #else // !Sun && !EMX 
 101                 void usleep(unsigned long usec
); 
 103         #endif // Sun/EMX/Something else 
 106     #define HAVE_USLEEP 1 
 107 #endif // Unices without usleep() 
 109 // ============================================================================ 
 111 // ============================================================================ 
 113 // ---------------------------------------------------------------------------- 
 115 // ---------------------------------------------------------------------------- 
 117 void wxSleep(int nSecs
) 
 122 void wxUsleep(unsigned long milliseconds
) 
 124 #if defined(HAVE_NANOSLEEP) 
 126     tmReq
.tv_sec 
= (time_t)(milliseconds 
/ 1000); 
 127     tmReq
.tv_nsec 
= (milliseconds 
% 1000) * 1000 * 1000; 
 129     // we're not interested in remaining time nor in return value 
 130     (void)nanosleep(&tmReq
, (timespec 
*)NULL
); 
 131 #elif defined(HAVE_USLEEP) 
 132     // uncomment this if you feel brave or if you are sure that your version 
 133     // of Solaris has a safe usleep() function but please notice that usleep() 
 134     // is known to lead to crashes in MT programs in Solaris 2.[67] and is not 
 135     // documented as MT-Safe 
 136     #if defined(__SUN__) && wxUSE_THREADS 
 137         #error "usleep() cannot be used in MT programs under Solaris." 
 140     usleep(milliseconds 
* 1000); // usleep(3) wants microseconds 
 141 #elif defined(HAVE_SLEEP) 
 142     // under BeOS sleep() takes seconds (what about other platforms, if any?) 
 143     sleep(milliseconds 
* 1000); 
 144 #else // !sleep function 
 145     #error "usleep() or nanosleep() function required for wxUsleep" 
 146 #endif // sleep function 
 149 // ---------------------------------------------------------------------------- 
 150 // process management 
 151 // ---------------------------------------------------------------------------- 
 153 int wxKill(long pid
, wxSignal sig
, wxKillError 
*rc
) 
 155     int err 
= kill((pid_t
)pid
, (int)sig
); 
 165                 *rc 
= wxKILL_BAD_SIGNAL
; 
 169                 *rc 
= wxKILL_ACCESS_DENIED
; 
 173                 *rc 
= wxKILL_NO_PROCESS
; 
 177                 // this goes against Unix98 docs so log it 
 178                 wxLogDebug(_T("unexpected kill(2) return value %d"), err
); 
 188 #define WXEXECUTE_NARGS   127 
 190 long wxExecute( const wxString
& command
, int flags
, wxProcess 
*process 
) 
 192     wxCHECK_MSG( !command
.IsEmpty(), 0, wxT("can't exec empty command") ); 
 195     wxChar 
*argv
[WXEXECUTE_NARGS
]; 
 197     const wxChar 
*cptr 
= command
.c_str(); 
 198     wxChar quotechar 
= wxT('\0'); // is arg quoted? 
 199     bool escaped 
= FALSE
; 
 201     // split the command line in arguments 
 205         quotechar 
= wxT('\0'); 
 207         // eat leading whitespace: 
 208         while ( wxIsspace(*cptr
) ) 
 211         if ( *cptr 
== wxT('\'') || *cptr 
== wxT('"') ) 
 216             if ( *cptr 
== wxT('\\') && ! escaped 
) 
 223             // all other characters: 
 227             // have we reached the end of the argument? 
 228             if ( (*cptr 
== quotechar 
&& ! escaped
) 
 229                  || (quotechar 
== wxT('\0') && wxIsspace(*cptr
)) 
 230                  || *cptr 
== wxT('\0') ) 
 232                 wxASSERT_MSG( argc 
< WXEXECUTE_NARGS
, 
 233                               wxT("too many arguments in wxExecute") ); 
 235                 argv
[argc
] = new wxChar
[argument
.length() + 1]; 
 236                 wxStrcpy(argv
[argc
], argument
.c_str()); 
 239                 // if not at end of buffer, swallow last character: 
 243                 break; // done with this one, start over 
 249     // do execute the command 
 250     long lRc 
= wxExecute(argv
, flags
, process
); 
 255         delete [] argv
[argc
++]; 
 260 // ---------------------------------------------------------------------------- 
 262 // ---------------------------------------------------------------------------- 
 264 static wxString 
wxMakeShellCommand(const wxString
& command
) 
 269         // just an interactive shell 
 274         // execute command in a shell 
 275         cmd 
<< _T("/bin/sh -c '") << command 
<< _T('\''); 
 281 bool wxShell(const wxString
& command
) 
 283     return wxExecute(wxMakeShellCommand(command
), wxEXEC_SYNC
) == 0; 
 286 bool wxShell(const wxString
& command
, wxArrayString
& output
) 
 288     wxCHECK_MSG( !!command
, FALSE
, _T("can't exec shell non interactively") ); 
 290     return wxExecute(wxMakeShellCommand(command
), output
); 
 295 void wxHandleProcessTermination(wxEndProcessData 
*proc_data
) 
 297     // notify user about termination if required 
 298     if ( proc_data
->process 
) 
 300         proc_data
->process
->OnTerminate(proc_data
->pid
, proc_data
->exitcode
); 
 304     if ( proc_data
->pid 
> 0 ) 
 310        // let wxExecute() know that the process has terminated 
 317 // ---------------------------------------------------------------------------- 
 318 // wxStream classes to support IO redirection in wxExecute 
 319 // ---------------------------------------------------------------------------- 
 323 class wxProcessFileInputStream 
: public wxInputStream
 
 326     wxProcessFileInputStream(int fd
) { m_fd 
= fd
; } 
 327     ~wxProcessFileInputStream() { close(m_fd
); } 
 329     virtual bool Eof() const; 
 332     size_t OnSysRead(void *buffer
, size_t bufsize
); 
 338 class wxProcessFileOutputStream 
: public wxOutputStream
 
 341     wxProcessFileOutputStream(int fd
) { m_fd 
= fd
; } 
 342     ~wxProcessFileOutputStream() { close(m_fd
); } 
 345     size_t OnSysWrite(const void *buffer
, size_t bufsize
); 
 351 bool wxProcessFileInputStream::Eof() const 
 353     if ( m_lasterror 
== wxSTREAM_EOF 
) 
 356     // check if there is any input available 
 363     FD_SET(m_fd
, &readfds
); 
 364     switch ( select(m_fd 
+ 1, &readfds
, NULL
, NULL
, &tv
) ) 
 367             wxLogSysError(_("Impossible to get child process input")); 
 374             wxFAIL_MSG(_T("unexpected select() return value")); 
 375             // still fall through 
 378             // input available: check if there is any 
 379             return wxInputStream::Eof(); 
 383 size_t wxProcessFileInputStream::OnSysRead(void *buffer
, size_t bufsize
) 
 385     int ret 
= read(m_fd
, buffer
, bufsize
); 
 388         m_lasterror 
= wxSTREAM_EOF
; 
 390     else if ( ret 
== -1 ) 
 392         m_lasterror 
= wxSTREAM_READ_ERROR
; 
 397         m_lasterror 
= wxSTREAM_NOERROR
; 
 403 size_t wxProcessFileOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
) 
 405     int ret 
= write(m_fd
, buffer
, bufsize
); 
 408         m_lasterror 
= wxSTREAM_WRITE_ERROR
; 
 413         m_lasterror 
= wxSTREAM_NOERROR
; 
 419 // ---------------------------------------------------------------------------- 
 420 // wxStreamTempBuffer 
 421 // ---------------------------------------------------------------------------- 
 424    Extract of a mail to wx-users to give the context of the problem we are 
 425    trying to solve here: 
 427     MC> If I run the command: 
 428     MC>    find . -name "*.h" -exec grep linux {} \; 
 429     MC> in the exec sample synchronously from the 'Capture command output' 
 430     MC> menu, wxExecute never returns.  I have to xkill it.  Has anyone 
 431     MC> else encountered this? 
 433      Yes, I can reproduce it too. 
 435      I even think I understand why it happens: before launching the external 
 436     command we set up a pipe with a valid file descriptor on the reading side 
 437     when the output is redirected. So the subprocess happily writes to it ... 
 438     until the pipe buffer (which is usually quite big on Unix, I think the 
 439     default is 4Mb) is full. Then the writing process stops and waits until we 
 440     read some data from the pipe to be able to continue writing to it but we 
 441     never do it because we wait until it terminates to start reading and so we 
 442     have a classical deadlock. 
 444    Here is the fix: we now read the output as soon as it appears into a temp 
 445    buffer (wxStreamTempBuffer object) and later just stuff it back into the 
 446    stream when the process terminates. See supporting code in wxExecute() 
 450 class wxStreamTempBuffer
 
 453     wxStreamTempBuffer(); 
 455     // call to associate a stream with this buffer, otherwise nothing happens 
 457     void Init(wxInputStream 
*stream
); 
 459     // check for input on our stream and cache it in our buffer if any 
 462     ~wxStreamTempBuffer(); 
 465     // the stream we're buffering, if NULL we don't do anything at all 
 466     wxInputStream 
*m_stream
; 
 468     // the buffer of size m_size (NULL if m_size == 0) 
 471     // the size of the buffer 
 475 wxStreamTempBuffer::wxStreamTempBuffer() 
 482 void wxStreamTempBuffer::Init(wxInputStream 
*stream
) 
 487 void wxStreamTempBuffer::Update() 
 489     if ( m_stream 
&& !m_stream
->Eof() ) 
 491         // realloc in blocks of 1Kb - surely not the best strategy but which 
 493         static const size_t incSize 
= 1024; 
 495         void *buf 
= realloc(m_buffer
, m_size 
+ incSize
); 
 498             // don't read any more, we don't have enough memory to do it 
 501         else // got memory for the buffer 
 504             m_stream
->Read((char *)m_buffer 
+ m_size
, incSize
); 
 510 wxStreamTempBuffer::~wxStreamTempBuffer() 
 514         m_stream
->Ungetch(m_buffer
, m_size
); 
 519 #endif // wxUSE_STREAMS 
 521 long wxExecute(wxChar 
**argv
, 
 525     // for the sync execution, we return -1 to indicate failure, but for async 
 526     // case we return 0 which is never a valid PID 
 528     // we define this as a macro, not a variable, to avoid compiler warnings 
 529     // about "ERROR_RETURN_CODE value may be clobbered by fork()" 
 530     #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0) 
 532     wxCHECK_MSG( *argv
, ERROR_RETURN_CODE
, wxT("can't exec empty command") ); 
 536     char *mb_argv
[WXEXECUTE_NARGS
]; 
 538     while (argv
[mb_argc
]) 
 540         wxWX2MBbuf mb_arg 
= wxConvertWX2MB(argv
[mb_argc
]); 
 541         mb_argv
[mb_argc
] = strdup(mb_arg
); 
 544     mb_argv
[mb_argc
] = (char *) NULL
; 
 546     // this macro will free memory we used above 
 547     #define ARGS_CLEANUP                                 \ 
 548         for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \ 
 549             free(mb_argv[mb_argc]) 
 551     // no need for cleanup 
 554     wxChar 
**mb_argv 
= argv
; 
 555 #endif // Unicode/ANSI 
 559     int end_proc_detect
[2]; 
 560     if ( pipe(end_proc_detect
) == -1 ) 
 562         wxLogSysError( _("Pipe creation failed") ); 
 563         wxLogError( _("Failed to execute '%s'\n"), *argv 
); 
 567         return ERROR_RETURN_CODE
; 
 571     // pipes for inter process communication 
 572     int pipeIn
[2],      // stdin 
 573         pipeOut
[2],     // stdout 
 574         pipeErr
[2];     // stderr 
 576     pipeIn
[0] = pipeIn
[1] = 
 577     pipeOut
[0] = pipeOut
[1] = 
 578     pipeErr
[0] = pipeErr
[1] = -1; 
 580     if ( process 
&& process
->IsRedirected() ) 
 582         if ( pipe(pipeIn
) == -1 || pipe(pipeOut
) == -1 || pipe(pipeErr
) == -1 ) 
 585             // free previously allocated resources 
 586             close(end_proc_detect
[0]); 
 587             close(end_proc_detect
[1]); 
 590             wxLogSysError( _("Pipe creation failed") ); 
 591             wxLogError( _("Failed to execute '%s'\n"), *argv 
); 
 595             return ERROR_RETURN_CODE
; 
 606     if ( pid 
== -1 )     // error? 
 609         close(end_proc_detect
[0]); 
 610         close(end_proc_detect
[1]); 
 619         wxLogSysError( _("Fork failed") ); 
 623         return ERROR_RETURN_CODE
; 
 625     else if ( pid 
== 0 )  // we're in child 
 628         close(end_proc_detect
[0]); // close reading side 
 631         // These lines close the open file descriptors to to avoid any 
 632         // input/output which might block the process or irritate the user. If 
 633         // one wants proper IO for the subprocess, the right thing to do is to 
 634         // start an xterm executing it. 
 635         if ( !(flags 
& wxEXEC_SYNC
) ) 
 637             for ( int fd 
= 0; fd 
< FD_SETSIZE
; fd
++ ) 
 639                 if ( fd 
== pipeIn
[0] || fd 
== pipeOut
[1] || fd 
== pipeErr
[1] 
 641                      || fd 
== end_proc_detect
[1] 
 645                     // don't close this one, we still need it 
 649                 // leave stderr opened too, it won't do any hurm 
 650                 if ( fd 
!= STDERR_FILENO 
) 
 655            if ( flags 
& wxEXEC_MAKE_GROUP_LEADER 
) 
 657                 // Set process group to child process' pid.  Then killing -pid 
 658                 // of the parent will kill the process and all of its children. 
 664         // redirect stdio, stdout and stderr 
 665         if ( pipeIn
[0] != -1 ) 
 667             if ( dup2(pipeIn
[0], STDIN_FILENO
) == -1 || 
 668                  dup2(pipeOut
[1], STDOUT_FILENO
) == -1 || 
 669                  dup2(pipeErr
[1], STDERR_FILENO
) == -1 ) 
 671                 wxLogSysError(_("Failed to redirect child process input/output")); 
 679         execvp (*mb_argv
, mb_argv
); 
 681         // there is no return after successful exec() 
 684         // some compilers complain about missing return - of course, they 
 685         // should know that exit() doesn't return but what else can we do if 
 687 #if defined(__VMS) || defined(__INTEL_COMPILER) 
 691     else // we're in parent 
 695         // pipe initialization: construction of the wxStreams 
 697         wxStreamTempBuffer bufIn
, bufErr
; 
 698 #endif // wxUSE_STREAMS 
 700         if ( process 
&& process
->IsRedirected() ) 
 703             // in/out for subprocess correspond to our out/in 
 704             wxOutputStream 
*outStream 
= new wxProcessFileOutputStream(pipeIn
[1]); 
 705             wxInputStream 
*inStream 
= new wxProcessFileInputStream(pipeOut
[0]); 
 706             wxInputStream 
*errStream 
= new wxProcessFileInputStream(pipeErr
[0]); 
 708             process
->SetPipeStreams(inStream
, outStream
, errStream
); 
 710             bufIn
.Init(inStream
); 
 711             bufErr
.Init(inStream
); 
 712 #endif // wxUSE_STREAMS 
 714             close(pipeIn
[0]); // close reading side 
 715             close(pipeOut
[1]); // close writing side 
 716             close(pipeErr
[1]); // close writing side 
 719 #if wxUSE_GUI && !defined(__WXMICROWIN__) 
 720         wxEndProcessData 
*data 
= new wxEndProcessData
; 
 722         if ( flags 
& wxEXEC_SYNC 
) 
 724             // we may have process for capturing the program output, but it's 
 725             // not used in wxEndProcessData in the case of sync execution 
 726             data
->process 
= NULL
; 
 728             // sync execution: indicate it by negating the pid 
 730             data
->tag 
= wxAddProcessCallback(data
, end_proc_detect
[0]); 
 732             close(end_proc_detect
[1]); // close writing side 
 737             // data->pid will be set to 0 from GTK_EndProcessDetector when the 
 738             // process terminates 
 739             while ( data
->pid 
!= 0 ) 
 744 #endif // wxUSE_STREAMS 
 746                 // give GTK+ a chance to call GTK_EndProcessDetector here and 
 747                 // also repaint the GUI 
 751             int exitcode 
= data
->exitcode
; 
 757         else // async execution 
 759             // async execution, nothing special to do - caller will be 
 760             // notified about the process termination if process != NULL, data 
 761             // will be deleted in GTK_EndProcessDetector 
 762             data
->process  
= process
; 
 764             data
->tag      
= wxAddProcessCallback(data
, end_proc_detect
[0]); 
 766             close(end_proc_detect
[1]); // close writing side 
 772         wxASSERT_MSG( flags 
& wxEXEC_SYNC
, 
 773                       wxT("async execution not supported yet") ); 
 776         if ( waitpid(pid
, &exitcode
, 0) == -1 || !WIFEXITED(exitcode
) ) 
 778             wxLogSysError(_("Waiting for subprocess termination failed")); 
 786 #undef ERROR_RETURN_CODE 
 789 // ---------------------------------------------------------------------------- 
 790 // file and directory functions 
 791 // ---------------------------------------------------------------------------- 
 793 const wxChar
* wxGetHomeDir( wxString 
*home  
) 
 795     *home 
= wxGetUserHome( wxString() ); 
 797     if ( home
->IsEmpty() ) 
 801    if ( tmp
.Last() != wxT(']')) 
 802      if ( tmp
.Last() != wxT('/')) *home 
<< wxT('/'); 
 804     return home
->c_str(); 
 808 const wxMB2WXbuf 
wxGetUserHome( const wxString 
&user 
) 
 809 #else // just for binary compatibility -- there is no 'const' here 
 810 char *wxGetUserHome( const wxString 
&user 
) 
 813     struct passwd 
*who 
= (struct passwd 
*) NULL
; 
 819         if ((ptr 
= wxGetenv(wxT("HOME"))) != NULL
) 
 823         if ((ptr 
= wxGetenv(wxT("USER"))) != NULL 
|| (ptr 
= wxGetenv(wxT("LOGNAME"))) != NULL
) 
 825             who 
= getpwnam(wxConvertWX2MB(ptr
)); 
 828         // We now make sure the the user exists! 
 831             who 
= getpwuid(getuid()); 
 836       who 
= getpwnam (user
.mb_str()); 
 839     return wxConvertMB2WX(who 
? who
->pw_dir 
: 0); 
 842 // ---------------------------------------------------------------------------- 
 843 // network and user id routines 
 844 // ---------------------------------------------------------------------------- 
 846 // retrieve either the hostname or FQDN depending on platform (caller must 
 847 // check whether it's one or the other, this is why this function is for 
 849 static bool wxGetHostNameInternal(wxChar 
*buf
, int sz
) 
 851     wxCHECK_MSG( buf
, FALSE
, wxT("NULL pointer in wxGetHostNameInternal") ); 
 855     // we're using uname() which is POSIX instead of less standard sysinfo() 
 856 #if defined(HAVE_UNAME) 
 858     bool ok 
= uname(&uts
) != -1; 
 861         wxStrncpy(buf
, wxConvertMB2WX(uts
.nodename
), sz 
- 1); 
 864 #elif defined(HAVE_GETHOSTNAME) 
 865     bool ok 
= gethostname(buf
, sz
) != -1; 
 866 #else // no uname, no gethostname 
 867     wxFAIL_MSG(wxT("don't know host name for this machine")); 
 870 #endif // uname/gethostname 
 874         wxLogSysError(_("Cannot get the hostname")); 
 880 bool wxGetHostName(wxChar 
*buf
, int sz
) 
 882     bool ok 
= wxGetHostNameInternal(buf
, sz
); 
 886         // BSD systems return the FQDN, we only want the hostname, so extract 
 887         // it (we consider that dots are domain separators) 
 888         wxChar 
*dot 
= wxStrchr(buf
, wxT('.')); 
 899 bool wxGetFullHostName(wxChar 
*buf
, int sz
) 
 901     bool ok 
= wxGetHostNameInternal(buf
, sz
); 
 905         if ( !wxStrchr(buf
, wxT('.')) ) 
 907             struct hostent 
*host 
= gethostbyname(wxConvertWX2MB(buf
)); 
 910                 wxLogSysError(_("Cannot get the official hostname")); 
 916                 // the canonical name 
 917                 wxStrncpy(buf
, wxConvertMB2WX(host
->h_name
), sz
); 
 920         //else: it's already a FQDN (BSD behaves this way) 
 926 bool wxGetUserId(wxChar 
*buf
, int sz
) 
 931     if ((who 
= getpwuid(getuid ())) != NULL
) 
 933         wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz 
- 1); 
 940 bool wxGetUserName(wxChar 
*buf
, int sz
) 
 945     if ((who 
= getpwuid (getuid ())) != NULL
) 
 947         // pw_gecos field in struct passwd is not standard 
 949        char *comma 
= strchr(who
->pw_gecos
, ','); 
 951            *comma 
= '\0'; // cut off non-name comment fields 
 952        wxStrncpy (buf
, wxConvertMB2WX(who
->pw_gecos
), sz 
- 1); 
 953 #else // !HAVE_PW_GECOS 
 954        wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz 
- 1); 
 955 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS 
 963 wxString 
wxGetOsDescription() 
 965 #ifndef WXWIN_OS_DESCRIPTION 
 966     #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure 
 968     return WXWIN_OS_DESCRIPTION
; 
 973 // this function returns the GUI toolkit version in GUI programs, but OS 
 974 // version in non-GUI ones 
 977 int wxGetOsVersion(int *majorVsn
, int *minorVsn
) 
 982     if ( sscanf(WXWIN_OS_DESCRIPTION
, "%s %d.%d", name
, &major
, &minor
) != 3 ) 
 984         // unreckognized uname string format 
 998 long wxGetFreeMemory() 
1000 #if defined(__LINUX__) 
1001     // get it from /proc/meminfo 
1002     FILE *fp 
= fopen("/proc/meminfo", "r"); 
1008         if ( fgets(buf
, WXSIZEOF(buf
), fp
) && fgets(buf
, WXSIZEOF(buf
), fp
) ) 
1010             long memTotal
, memUsed
; 
1011             sscanf(buf
, "Mem: %ld %ld %ld", &memTotal
, &memUsed
, &memFree
); 
1018 #elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES) 
1019     return sysconf(_SC_AVPHYS_PAGES
)*sysconf(_SC_PAGESIZE
); 
1020 //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably 
1023     // can't find it out 
1027 bool wxGetDiskSpace(const wxString
& path
, wxLongLong 
*pTotal
, wxLongLong 
*pFree
) 
1029 #if defined(HAVE_STATFS) || defined(HAVE_STATVFS) 
1030     // the case to "char *" is needed for AIX 4.3 
1032     if ( statfs((char *)path
.fn_str(), &fs
) != 0 ) 
1034         wxLogSysError("Failed to get file system statistics"); 
1039     // under Solaris we might have to use fs.f_frsize instead as I think it 
1040     // may be a multiple of the block size in general (TODO) 
1044         *pTotal 
= wxLongLong(fs
.f_blocks
) * fs
.f_bsize
; 
1049         *pFree 
= wxLongLong(fs
.f_bavail
) * fs
.f_bsize
; 
1053 #endif // HAVE_STATFS 
1058 // ---------------------------------------------------------------------------- 
1060 // ---------------------------------------------------------------------------- 
1062 bool wxGetEnv(const wxString
& var
, wxString 
*value
) 
1064     // wxGetenv is defined as getenv() 
1065     wxChar 
*p 
= wxGetenv(var
); 
1077 bool wxSetEnv(const wxString
& variable
, const wxChar 
*value
) 
1079 #if defined(HAVE_SETENV) 
1080     return setenv(variable
.mb_str(), 
1081                   value 
? (const char *)wxString(value
).mb_str() 
1083                   1 /* overwrite */) == 0; 
1084 #elif defined(HAVE_PUTENV) 
1085     wxString s 
= variable
; 
1087         s 
<< _T('=') << value
; 
1089     // transform to ANSI 
1090     const char *p 
= s
.mb_str(); 
1092     // the string will be free()d by libc 
1093     char *buf 
= (char *)malloc(strlen(p
) + 1); 
1096     return putenv(buf
) == 0; 
1097 #else // no way to set an env var 
1102 // ---------------------------------------------------------------------------- 
1104 // ---------------------------------------------------------------------------- 
1106 #if wxUSE_ON_FATAL_EXCEPTION 
1110 extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER
) 
1114         // give the user a chance to do something special about this 
1115         wxTheApp
->OnFatalException(); 
1121 bool wxHandleFatalExceptions(bool doit
) 
1124     static bool s_savedHandlers 
= FALSE
; 
1125     static struct sigaction s_handlerFPE
, 
1131     if ( doit 
&& !s_savedHandlers 
) 
1133         // install the signal handler 
1134         struct sigaction act
; 
1136         // some systems extend it with non std fields, so zero everything 
1137         memset(&act
, 0, sizeof(act
)); 
1139         act
.sa_handler 
= wxFatalSignalHandler
; 
1140         sigemptyset(&act
.sa_mask
); 
1143         ok 
&= sigaction(SIGFPE
, &act
, &s_handlerFPE
) == 0; 
1144         ok 
&= sigaction(SIGILL
, &act
, &s_handlerILL
) == 0; 
1145         ok 
&= sigaction(SIGBUS
, &act
, &s_handlerBUS
) == 0; 
1146         ok 
&= sigaction(SIGSEGV
, &act
, &s_handlerSEGV
) == 0; 
1149             wxLogDebug(_T("Failed to install our signal handler.")); 
1152         s_savedHandlers 
= TRUE
; 
1154     else if ( s_savedHandlers 
) 
1156         // uninstall the signal handler 
1157         ok 
&= sigaction(SIGFPE
, &s_handlerFPE
, NULL
) == 0; 
1158         ok 
&= sigaction(SIGILL
, &s_handlerILL
, NULL
) == 0; 
1159         ok 
&= sigaction(SIGBUS
, &s_handlerBUS
, NULL
) == 0; 
1160         ok 
&= sigaction(SIGSEGV
, &s_handlerSEGV
, NULL
) == 0; 
1163             wxLogDebug(_T("Failed to uninstall our signal handler.")); 
1166         s_savedHandlers 
= FALSE
; 
1168     //else: nothing to do 
1173 #endif // wxUSE_ON_FATAL_EXCEPTION 
1175 // ---------------------------------------------------------------------------- 
1176 // error and debug output routines (deprecated, use wxLog) 
1177 // ---------------------------------------------------------------------------- 
1179 #if WXWIN_COMPATIBILITY_2_2 
1181 void wxDebugMsg( const char *format
, ... ) 
1184   va_start( ap
, format 
); 
1185   vfprintf( stderr
, format
, ap 
); 
1190 void wxError( const wxString 
&msg
, const wxString 
&title 
) 
1192   wxFprintf( stderr
, _("Error ") ); 
1193   if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) ); 
1194   if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) ); 
1195   wxFprintf( stderr
, wxT(".\n") ); 
1198 void wxFatalError( const wxString 
&msg
, const wxString 
&title 
) 
1200   wxFprintf( stderr
, _("Error ") ); 
1201   if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) ); 
1202   if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) ); 
1203   wxFprintf( stderr
, wxT(".\n") ); 
1204   exit(3); // the same exit code as for abort() 
1207 #endif // WXWIN_COMPATIBILITY_2_2