home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / unix / utilsunx.cpp < prev    next >
C/C++ Source or Header  |  2002-11-17  |  34KB  |  1,210 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        unix/utilsunx.cpp
  3. // Purpose:     generic Unix implementation of many wx functions
  4. // Author:      Vadim Zeitlin
  5. // Id:          $Id: utilsunx.cpp,v 1.86.2.4 2002/11/14 13:51:57 GD Exp $
  6. // Copyright:   (c) 1998 Robert Roebling, Vadim Zeitlin
  7. // Licence:     wxWindows licence
  8. /////////////////////////////////////////////////////////////////////////////
  9.  
  10. // ============================================================================
  11. // declarations
  12. // ============================================================================
  13.  
  14. // ----------------------------------------------------------------------------
  15. // headers
  16. // ----------------------------------------------------------------------------
  17.  
  18. #include "wx/defs.h"
  19. #include "wx/string.h"
  20.  
  21. #include "wx/intl.h"
  22. #include "wx/log.h"
  23. #include "wx/app.h"
  24.  
  25. #include "wx/utils.h"
  26. #include "wx/process.h"
  27. #include "wx/thread.h"
  28.  
  29. #include "wx/wfstream.h"
  30.  
  31. #ifdef HAVE_STATFS
  32. #  ifdef __BSD__
  33. #    include <sys/param.h>
  34. #    include <sys/mount.h>
  35. #  else
  36. #    include <sys/vfs.h>
  37. #  endif
  38. #endif // HAVE_STATFS
  39.  
  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
  43. #ifdef HAVE_STATVFS
  44.     #include <sys/statvfs.h>
  45.  
  46.     #define statfs statvfs
  47. # ifdef __HPUX__
  48.     #define wxStatFs struct statvfs
  49. # else
  50.     #define wxStatFs statvfs_t
  51. # endif
  52. #elif HAVE_STATFS
  53.     #define wxStatFs struct statfs
  54. #endif // HAVE_STAT[V]FS
  55.  
  56. #if wxUSE_GUI
  57.     #include "wx/unix/execute.h"
  58. #endif
  59.  
  60. // SGI signal.h defines signal handler arguments differently depending on
  61. // whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it
  62. #if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS)
  63.     #define _LANGUAGE_C_PLUS_PLUS 1
  64. #endif // SGI hack
  65.  
  66. #include <stdarg.h>
  67. #include <dirent.h>
  68. #include <string.h>
  69. #include <sys/stat.h>
  70. #include <sys/types.h>
  71. #include <unistd.h>
  72. #include <sys/wait.h>
  73. #include <pwd.h>
  74. #include <errno.h>
  75. #include <netdb.h>
  76. #include <signal.h>
  77. #include <fcntl.h>          // for O_WRONLY and friends
  78. #include <time.h>           // nanosleep() and/or usleep()
  79. #include <ctype.h>          // isspace()
  80. #include <sys/time.h>       // needed for FD_SETSIZE
  81.  
  82. #ifdef HAVE_UNAME
  83.     #include <sys/utsname.h> // for uname()
  84. #endif // HAVE_UNAME
  85.  
  86. // ----------------------------------------------------------------------------
  87. // conditional compilation
  88. // ----------------------------------------------------------------------------
  89.  
  90. // many versions of Unices have this function, but it is not defined in system
  91. // headers - please add your system here if it is the case for your OS.
  92. // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
  93. #if !defined(HAVE_USLEEP) && \
  94.     (defined(__SUN__) && !defined(__SunOs_5_6) && \
  95.                          !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
  96.      defined(__osf__) || defined(__EMX__)
  97.     extern "C"
  98.     {
  99.         #ifdef __SUN__
  100.             int usleep(unsigned int usec);
  101.         #else // !Sun
  102.             #ifdef __EMX__
  103.                 /* I copied this from the XFree86 diffs. AV. */
  104.                 #define INCL_DOSPROCESS
  105.                 #include <os2.h>
  106.                 inline void usleep(unsigned long delay)
  107.                 {
  108.                     DosSleep(delay ? (delay/1000l) : 1l);
  109.                 }
  110.             #else // !Sun && !EMX
  111.                 void usleep(unsigned long usec);
  112.             #endif
  113.         #endif // Sun/EMX/Something else
  114.     };
  115.  
  116.     #define HAVE_USLEEP 1
  117. #endif // Unices without usleep()
  118.  
  119. // ============================================================================
  120. // implementation
  121. // ============================================================================
  122.  
  123. // ----------------------------------------------------------------------------
  124. // sleeping
  125. // ----------------------------------------------------------------------------
  126.  
  127. void wxSleep(int nSecs)
  128. {
  129.     sleep(nSecs);
  130. }
  131.  
  132. void wxUsleep(unsigned long milliseconds)
  133. {
  134. #if defined(HAVE_NANOSLEEP)
  135.     timespec tmReq;
  136.     tmReq.tv_sec = (time_t)(milliseconds / 1000);
  137.     tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
  138.  
  139.     // we're not interested in remaining time nor in return value
  140.     (void)nanosleep(&tmReq, (timespec *)NULL);
  141. #elif defined(HAVE_USLEEP)
  142.     // uncomment this if you feel brave or if you are sure that your version
  143.     // of Solaris has a safe usleep() function but please notice that usleep()
  144.     // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
  145.     // documented as MT-Safe
  146.     #if defined(__SUN__) && wxUSE_THREADS
  147.         #error "usleep() cannot be used in MT programs under Solaris."
  148.     #endif // Sun
  149.  
  150.     usleep(milliseconds * 1000); // usleep(3) wants microseconds
  151. #elif defined(HAVE_SLEEP)
  152.     // under BeOS sleep() takes seconds (what about other platforms, if any?)
  153.     sleep(milliseconds * 1000);
  154. #else // !sleep function
  155.     #error "usleep() or nanosleep() function required for wxUsleep"
  156. #endif // sleep function
  157. }
  158.  
  159. // ----------------------------------------------------------------------------
  160. // process management
  161. // ----------------------------------------------------------------------------
  162.  
  163. int wxKill(long pid, wxSignal sig, wxKillError *rc)
  164. {
  165.     int err = kill((pid_t)pid, (int)sig);
  166.     if ( rc )
  167.     {
  168.         switch ( errno )
  169.         {
  170.             case 0:
  171.                 *rc = wxKILL_OK;
  172.                 break;
  173.  
  174.             case EINVAL:
  175.                 *rc = wxKILL_BAD_SIGNAL;
  176.                 break;
  177.  
  178.             case EPERM:
  179.                 *rc = wxKILL_ACCESS_DENIED;
  180.                 break;
  181.  
  182.             case ESRCH:
  183.                 *rc = wxKILL_NO_PROCESS;
  184.                 break;
  185.  
  186.             default:
  187.                 // this goes against Unix98 docs so log it
  188.                 wxLogDebug(_T("unexpected kill(2) return value %d"), err);
  189.  
  190.                 // something else...
  191.                 *rc = wxKILL_ERROR;
  192.         }
  193.     }
  194.  
  195.     return err;
  196. }
  197.  
  198. #define WXEXECUTE_NARGS   127
  199.  
  200. long wxExecute( const wxString& command, int flags, wxProcess *process )
  201. {
  202.     wxCHECK_MSG( !command.IsEmpty(), 0, wxT("can't exec empty command") );
  203.  
  204.     int argc = 0;
  205.     wxChar *argv[WXEXECUTE_NARGS];
  206.     wxString argument;
  207.     const wxChar *cptr = command.c_str();
  208.     wxChar quotechar = wxT('\0'); // is arg quoted?
  209.     bool escaped = FALSE;
  210.  
  211.     // split the command line in arguments
  212.     do
  213.     {
  214.         argument=wxT("");
  215.         quotechar = wxT('\0');
  216.  
  217.         // eat leading whitespace:
  218.         while ( wxIsspace(*cptr) )
  219.             cptr++;
  220.  
  221.         if ( *cptr == wxT('\'') || *cptr == wxT('"') )
  222.             quotechar = *cptr++;
  223.  
  224.         do
  225.         {
  226.             if ( *cptr == wxT('\\') && ! escaped )
  227.             {
  228.                 escaped = TRUE;
  229.                 cptr++;
  230.                 continue;
  231.             }
  232.  
  233.             // all other characters:
  234.             argument += *cptr++;
  235.             escaped = FALSE;
  236.  
  237.             // have we reached the end of the argument?
  238.             if ( (*cptr == quotechar && ! escaped)
  239.                  || (quotechar == wxT('\0') && wxIsspace(*cptr))
  240.                  || *cptr == wxT('\0') )
  241.             {
  242.                 wxASSERT_MSG( argc < WXEXECUTE_NARGS,
  243.                               wxT("too many arguments in wxExecute") );
  244.  
  245.                 argv[argc] = new wxChar[argument.length() + 1];
  246.                 wxStrcpy(argv[argc], argument.c_str());
  247.                 argc++;
  248.  
  249.                 // if not at end of buffer, swallow last character:
  250.                 if(*cptr)
  251.                     cptr++;
  252.  
  253.                 break; // done with this one, start over
  254.             }
  255.         } while(*cptr);
  256.     } while(*cptr);
  257.     argv[argc] = NULL;
  258.  
  259.     // do execute the command
  260.     long lRc = wxExecute(argv, flags, process);
  261.  
  262.     // clean up
  263.     argc = 0;
  264.     while( argv[argc] )
  265.         delete [] argv[argc++];
  266.  
  267.     return lRc;
  268. }
  269.  
  270. // ----------------------------------------------------------------------------
  271. // wxShell
  272. // ----------------------------------------------------------------------------
  273.  
  274. static wxString wxMakeShellCommand(const wxString& command)
  275. {
  276.     wxString cmd;
  277.     if ( !command )
  278.     {
  279.         // just an interactive shell
  280.         cmd = _T("xterm");
  281.     }
  282.     else
  283.     {
  284.         // execute command in a shell
  285.         cmd << _T("/bin/sh -c '") << command << _T('\'');
  286.     }
  287.  
  288.     return cmd;
  289. }
  290.  
  291. bool wxShell(const wxString& command)
  292. {
  293.     return wxExecute(wxMakeShellCommand(command), wxEXEC_SYNC) == 0;
  294. }
  295.  
  296. bool wxShell(const wxString& command, wxArrayString& output)
  297. {
  298.     wxCHECK_MSG( !!command, FALSE, _T("can't exec shell non interactively") );
  299.  
  300.     return wxExecute(wxMakeShellCommand(command), output);
  301. }
  302.  
  303. // Shutdown or reboot the PC
  304. bool wxShutdown(wxShutdownFlags wFlags)
  305. {
  306.     wxChar level;
  307.     switch ( wFlags )
  308.     {
  309.         case wxSHUTDOWN_POWEROFF:
  310.             level = _T('0');
  311.             break;
  312.  
  313.         case wxSHUTDOWN_REBOOT:
  314.             level = _T('6');
  315.             break;
  316.  
  317.         default:
  318.             wxFAIL_MSG( _T("unknown wxShutdown() flag") );
  319.             return FALSE;
  320.     }
  321.  
  322.     return system(wxString::Format(_T("init %c"), level).mb_str()) == 0;
  323. }
  324.  
  325.  
  326. #if wxUSE_GUI
  327.  
  328. void wxHandleProcessTermination(wxEndProcessData *proc_data)
  329. {
  330.     // notify user about termination if required
  331.     if ( proc_data->process )
  332.     {
  333.         proc_data->process->OnTerminate(proc_data->pid, proc_data->exitcode);
  334.     }
  335.  
  336.     // clean up
  337.     if ( proc_data->pid > 0 )
  338.     {
  339.        delete proc_data;
  340.     }
  341.     else
  342.     {
  343.        // let wxExecute() know that the process has terminated
  344.        proc_data->pid = 0;
  345.     }
  346. }
  347.  
  348. #endif // wxUSE_GUI
  349.  
  350. // ----------------------------------------------------------------------------
  351. // wxStream classes to support IO redirection in wxExecute
  352. // ----------------------------------------------------------------------------
  353.  
  354. #if wxUSE_STREAMS
  355.  
  356. // ----------------------------------------------------------------------------
  357. // wxPipeInputStream: stream for reading from a pipe
  358. // ----------------------------------------------------------------------------
  359.  
  360. class wxPipeInputStream : public wxFileInputStream
  361. {
  362. public:
  363.     wxPipeInputStream(int fd) : wxFileInputStream(fd) { }
  364.  
  365.     // return TRUE if the pipe is still opened
  366.     bool IsOpened() const { return !Eof(); }
  367.  
  368.     // return TRUE if we have anything to read, don't block
  369.     virtual bool CanRead() const;
  370. };
  371.  
  372. bool wxPipeInputStream::CanRead() const
  373. {
  374.     if ( m_lasterror == wxSTREAM_EOF )
  375.         return FALSE;
  376.  
  377.     // check if there is any input available
  378.     struct timeval tv;
  379.     tv.tv_sec = 0;
  380.     tv.tv_usec = 0;
  381.  
  382.     const int fd = m_file->fd();
  383.  
  384.     fd_set readfds;
  385.     FD_ZERO(&readfds);
  386.     FD_SET(fd, &readfds);
  387.     switch ( select(fd + 1, &readfds, NULL, NULL, &tv) )
  388.     {
  389.         case -1:
  390.             wxLogSysError(_("Impossible to get child process input"));
  391.             // fall through
  392.  
  393.         case 0:
  394.             return FALSE;
  395.  
  396.         default:
  397.             wxFAIL_MSG(_T("unexpected select() return value"));
  398.             // still fall through
  399.  
  400.         case 1:
  401.             // input available -- or maybe not, as select() returns 1 when a
  402.             // read() will complete without delay, but it could still not read
  403.             // anything
  404.             return !Eof();
  405.     }
  406. }
  407.  
  408. // define this to let wxexec.cpp know that we know what we're doing
  409. #define _WX_USED_BY_WXEXECUTE_
  410. #include "../common/execcmn.cpp"
  411.  
  412. #endif // wxUSE_STREAMS
  413.  
  414. // ----------------------------------------------------------------------------
  415. // wxPipe: this encapsulates pipe() system call
  416. // ----------------------------------------------------------------------------
  417.  
  418. class wxPipe
  419. {
  420. public:
  421.     // the symbolic names for the pipe ends
  422.     enum Direction
  423.     {
  424.         Read,
  425.         Write
  426.     };
  427.  
  428.     enum
  429.     {
  430.         INVALID_FD = -1
  431.     };
  432.  
  433.     // default ctor doesn't do anything
  434.     wxPipe() { m_fds[Read] = m_fds[Write] = INVALID_FD; }
  435.  
  436.     // create the pipe, return TRUE if ok, FALSE on error
  437.     bool Create()
  438.     {
  439.         if ( pipe(m_fds) == -1 )
  440.         {
  441.             wxLogSysError(_("Pipe creation failed"));
  442.  
  443.             return FALSE;
  444.         }
  445.  
  446.         return TRUE;
  447.     }
  448.  
  449.     // return TRUE if we were created successfully
  450.     bool IsOk() const { return m_fds[Read] != INVALID_FD; }
  451.  
  452.     // return the descriptor for one of the pipe ends
  453.     int operator[](Direction which) const
  454.     {
  455.         wxASSERT_MSG( which >= 0 && (size_t)which < WXSIZEOF(m_fds),
  456.                       _T("invalid pipe index") );
  457.  
  458.         return m_fds[which];
  459.     }
  460.  
  461.     // detach a descriptor, meaning that the pipe dtor won't close it, and
  462.     // return it
  463.     int Detach(Direction which)
  464.     {
  465.         wxASSERT_MSG( which >= 0 && (size_t)which < WXSIZEOF(m_fds),
  466.                       _T("invalid pipe index") );
  467.  
  468.         int fd = m_fds[which];
  469.         m_fds[which] = INVALID_FD;
  470.  
  471.         return fd;
  472.     }
  473.  
  474.     // close the pipe descriptors
  475.     void Close()
  476.     {
  477.         for ( size_t n = 0; n < WXSIZEOF(m_fds); n++ )
  478.         {
  479.             if ( m_fds[n] != INVALID_FD )
  480.                 close(m_fds[n]);
  481.         }
  482.     }
  483.  
  484.     // dtor closes the pipe descriptors
  485.     ~wxPipe() { Close(); }
  486.  
  487. private:
  488.     int m_fds[2];
  489. };
  490.  
  491. // ----------------------------------------------------------------------------
  492. // wxExecute: the real worker function
  493. // ----------------------------------------------------------------------------
  494.  
  495. #ifdef __VMS
  496.     #pragma message disable codeunreachable
  497. #endif
  498.  
  499. long wxExecute(wxChar **argv,
  500.                int flags,
  501.                wxProcess *process)
  502. {
  503.     // for the sync execution, we return -1 to indicate failure, but for async
  504.     // case we return 0 which is never a valid PID
  505.     //
  506.     // we define this as a macro, not a variable, to avoid compiler warnings
  507.     // about "ERROR_RETURN_CODE value may be clobbered by fork()"
  508.     #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)
  509.  
  510.     wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") );
  511.  
  512. #if wxUSE_UNICODE
  513.     int mb_argc = 0;
  514.     char *mb_argv[WXEXECUTE_NARGS];
  515.  
  516.     while (argv[mb_argc])
  517.     {
  518.         wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
  519.         mb_argv[mb_argc] = strdup(mb_arg);
  520.         mb_argc++;
  521.     }
  522.     mb_argv[mb_argc] = (char *) NULL;
  523.  
  524.     // this macro will free memory we used above
  525.     #define ARGS_CLEANUP                                 \
  526.         for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
  527.             free(mb_argv[mb_argc])
  528. #else // ANSI
  529.     // no need for cleanup
  530.     #define ARGS_CLEANUP
  531.  
  532.     wxChar **mb_argv = argv;
  533. #endif // Unicode/ANSI
  534.  
  535. #if wxUSE_GUI
  536.     // create pipes
  537.     wxPipe pipeEndProcDetect;
  538.     if ( !pipeEndProcDetect.Create() )
  539.     {
  540.         wxLogError( _("Failed to execute '%s'\n"), *argv );
  541.  
  542.         ARGS_CLEANUP;
  543.  
  544.         return ERROR_RETURN_CODE;
  545.     }
  546. #endif // wxUSE_GUI
  547.  
  548.     // pipes for inter process communication
  549.     wxPipe pipeIn,      // stdin
  550.            pipeOut,     // stdout
  551.            pipeErr;     // stderr
  552.  
  553.     if ( process && process->IsRedirected() )
  554.     {
  555.         if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
  556.         {
  557.             wxLogError( _("Failed to execute '%s'\n"), *argv );
  558.  
  559.             ARGS_CLEANUP;
  560.  
  561.             return ERROR_RETURN_CODE;
  562.         }
  563.     }
  564.  
  565.     // fork the process
  566.     //
  567.     // NB: do *not* use vfork() here, it completely breaks this code for some
  568.     //     reason under Solaris (and maybe others, although not under Linux)
  569.     //     But on OpenVMS we do not have fork so we have to use vfork and
  570.     //     cross our fingers that it works.
  571. #ifdef __VMS
  572.    pid_t pid = vfork();
  573. #else
  574.    pid_t pid = fork();
  575. #endif
  576.    if ( pid == -1 )     // error?
  577.     {
  578.         wxLogSysError( _("Fork failed") );
  579.  
  580.         ARGS_CLEANUP;
  581.  
  582.         return ERROR_RETURN_CODE;
  583.     }
  584.     else if ( pid == 0 )  // we're in child
  585.     {
  586.         // These lines close the open file descriptors to to avoid any
  587.         // input/output which might block the process or irritate the user. If
  588.         // one wants proper IO for the subprocess, the right thing to do is to
  589.         // start an xterm executing it.
  590.         if ( !(flags & wxEXEC_SYNC) )
  591.         {
  592.             for ( int fd = 0; fd < FD_SETSIZE; fd++ )
  593.             {
  594.                 if ( fd == pipeIn[wxPipe::Read]
  595.                         || fd == pipeOut[wxPipe::Write]
  596.                         || fd == pipeErr[wxPipe::Write]
  597. #if wxUSE_GUI
  598.                         || fd == pipeEndProcDetect[wxPipe::Write]
  599. #endif // wxUSE_GUI
  600.                    )
  601.                 {
  602.                     // don't close this one, we still need it
  603.                     continue;
  604.                 }
  605.  
  606.                 // leave stderr opened too, it won't do any harm
  607.                 if ( fd != STDERR_FILENO )
  608.                     close(fd);
  609.             }
  610.         }
  611.  
  612. #if !defined(__VMS) && !defined(__EMX__)
  613.         if ( flags & wxEXEC_MAKE_GROUP_LEADER )
  614.         {
  615.             // Set process group to child process' pid.  Then killing -pid
  616.             // of the parent will kill the process and all of its children.
  617.             setsid();
  618.         }
  619. #endif // !__VMS
  620.  
  621. #if wxUSE_GUI
  622.         // reading side can be safely closed but we should keep the write one
  623.         // opened
  624.         pipeEndProcDetect.Detach(wxPipe::Write);
  625.         pipeEndProcDetect.Close();
  626. #endif // wxUSE_GUI
  627.  
  628.         // redirect stdin, stdout and stderr
  629.         if ( pipeIn.IsOk() )
  630.         {
  631.             if ( dup2(pipeIn[wxPipe::Read], STDIN_FILENO) == -1 ||
  632.                  dup2(pipeOut[wxPipe::Write], STDOUT_FILENO) == -1 ||
  633.                  dup2(pipeErr[wxPipe::Write], STDERR_FILENO) == -1 )
  634.             {
  635.                 wxLogSysError(_("Failed to redirect child process input/output"));
  636.             }
  637.  
  638.             pipeIn.Close();
  639.             pipeOut.Close();
  640.             pipeErr.Close();
  641.         }
  642.  
  643.         execvp (*mb_argv, mb_argv);
  644.  
  645.         // there is no return after successful exec()
  646.         _exit(-1);
  647.  
  648.         // some compilers complain about missing return - of course, they
  649.         // should know that exit() doesn't return but what else can we do if
  650.         // they don't?
  651.         //
  652.         // and, sure enough, other compilers complain about unreachable code
  653.         // after exit() call, so we can just always have return here...
  654. #if defined(__VMS) || defined(__INTEL_COMPILER)
  655.         return 0;
  656. #endif
  657.     }
  658.     else // we're in parent
  659.     {
  660.         ARGS_CLEANUP;
  661.  
  662.         // prepare for IO redirection
  663.  
  664. #if wxUSE_STREAMS
  665.         // the input buffer bufOut is connected to stdout, this is why it is
  666.         // called bufOut and not bufIn
  667.         wxStreamTempInputBuffer bufOut,
  668.                                 bufErr;
  669. #endif // wxUSE_STREAMS
  670.  
  671.         if ( process && process->IsRedirected() )
  672.         {
  673. #if wxUSE_STREAMS
  674.             wxOutputStream *inStream =
  675.                 new wxFileOutputStream(pipeIn.Detach(wxPipe::Write));
  676.  
  677.             wxPipeInputStream *outStream =
  678.                 new wxPipeInputStream(pipeOut.Detach(wxPipe::Read));
  679.  
  680.             wxPipeInputStream *errStream =
  681.                 new wxPipeInputStream(pipeErr.Detach(wxPipe::Read));
  682.  
  683.             process->SetPipeStreams(outStream, inStream, errStream);
  684.  
  685.             bufOut.Init(outStream);
  686.             bufErr.Init(errStream);
  687. #endif // wxUSE_STREAMS
  688.         }
  689.  
  690.         if ( pipeIn.IsOk() )
  691.         {
  692.             pipeIn.Close();
  693.             pipeOut.Close();
  694.             pipeErr.Close();
  695.         }
  696.  
  697. #if wxUSE_GUI && !defined(__WXMICROWIN__)
  698.         wxEndProcessData *data = new wxEndProcessData;
  699.  
  700.         data->tag = wxAddProcessCallback
  701.                     (
  702.                         data,
  703.                         pipeEndProcDetect.Detach(wxPipe::Read)
  704.                     );
  705.  
  706.         pipeEndProcDetect.Close();
  707.  
  708.         if ( flags & wxEXEC_SYNC )
  709.         {
  710.             // we may have process for capturing the program output, but it's
  711.             // not used in wxEndProcessData in the case of sync execution
  712.             data->process = NULL;
  713.  
  714.             // sync execution: indicate it by negating the pid
  715.             data->pid = -pid;
  716.  
  717.             wxBusyCursor bc;
  718.             wxWindowDisabler wd;
  719.  
  720.             // data->pid will be set to 0 from GTK_EndProcessDetector when the
  721.             // process terminates
  722.             while ( data->pid != 0 )
  723.             {
  724. #if wxUSE_STREAMS
  725.                 bufOut.Update();
  726.                 bufErr.Update();
  727. #endif // wxUSE_STREAMS
  728.  
  729.                 // give GTK+ a chance to call GTK_EndProcessDetector here and
  730.                 // also repaint the GUI
  731.                 wxYield();
  732.             }
  733.  
  734.             int exitcode = data->exitcode;
  735.  
  736.             delete data;
  737.  
  738.             return exitcode;
  739.         }
  740.         else // async execution
  741.         {
  742.             // async execution, nothing special to do - caller will be
  743.             // notified about the process termination if process != NULL, data
  744.             // will be deleted in GTK_EndProcessDetector
  745.             data->process  = process;
  746.             data->pid      = pid;
  747.  
  748.             return pid;
  749.         }
  750. #else // !wxUSE_GUI
  751.  
  752.         wxASSERT_MSG( flags & wxEXEC_SYNC,
  753.                       wxT("async execution not supported yet") );
  754.  
  755.         int exitcode = 0;
  756.         if ( waitpid(pid, &exitcode, 0) == -1 || !WIFEXITED(exitcode) )
  757.         {
  758.             wxLogSysError(_("Waiting for subprocess termination failed"));
  759.         }
  760.  
  761.         return exitcode;
  762. #endif // wxUSE_GUI
  763.     }
  764.  
  765.     return ERROR_RETURN_CODE;
  766. }
  767.  
  768. #ifdef __VMS
  769.     #pragma message enable codeunreachable
  770. #endif
  771.  
  772. #undef ERROR_RETURN_CODE
  773. #undef ARGS_CLEANUP
  774.  
  775. // ----------------------------------------------------------------------------
  776. // file and directory functions
  777. // ----------------------------------------------------------------------------
  778.  
  779. const wxChar* wxGetHomeDir( wxString *home  )
  780. {
  781.     *home = wxGetUserHome( wxString() );
  782.     wxString tmp;
  783.     if ( home->IsEmpty() )
  784.         *home = wxT("/");
  785. #ifdef __VMS
  786.     tmp = *home;
  787.     if ( tmp.Last() != wxT(']'))
  788.         if ( tmp.Last() != wxT('/')) *home << wxT('/');
  789. #endif
  790.     return home->c_str();
  791. }
  792.  
  793. #if wxUSE_UNICODE
  794. const wxMB2WXbuf wxGetUserHome( const wxString &user )
  795. #else // just for binary compatibility -- there is no 'const' here
  796. char *wxGetUserHome( const wxString &user )
  797. #endif
  798. {
  799.     struct passwd *who = (struct passwd *) NULL;
  800.  
  801.     if ( !user )
  802.     {
  803.         wxChar *ptr;
  804.  
  805.         if ((ptr = wxGetenv(wxT("HOME"))) != NULL)
  806.         {
  807. #if wxUSE_UNICODE
  808.             wxWCharBuffer buffer( ptr );
  809.             return buffer;
  810. #else
  811.             return ptr;
  812. #endif
  813.         }
  814.         if ((ptr = wxGetenv(wxT("USER"))) != NULL || (ptr = wxGetenv(wxT("LOGNAME"))) != NULL)
  815.         {
  816.             who = getpwnam(wxConvertWX2MB(ptr));
  817.         }
  818.  
  819.         // We now make sure the the user exists!
  820.         if (who == NULL)
  821.         {
  822.             who = getpwuid(getuid());
  823.         }
  824.     }
  825.     else
  826.     {
  827.       who = getpwnam (user.mb_str());
  828.     }
  829.  
  830.     return wxConvertMB2WX(who ? who->pw_dir : 0);
  831. }
  832.  
  833. // ----------------------------------------------------------------------------
  834. // network and user id routines
  835. // ----------------------------------------------------------------------------
  836.  
  837. // retrieve either the hostname or FQDN depending on platform (caller must
  838. // check whether it's one or the other, this is why this function is for
  839. // private use only)
  840. static bool wxGetHostNameInternal(wxChar *buf, int sz)
  841. {
  842.     wxCHECK_MSG( buf, FALSE, wxT("NULL pointer in wxGetHostNameInternal") );
  843.  
  844.     *buf = wxT('\0');
  845.  
  846.     // we're using uname() which is POSIX instead of less standard sysinfo()
  847. #if defined(HAVE_UNAME)
  848.     struct utsname uts;
  849.     bool ok = uname(&uts) != -1;
  850.     if ( ok )
  851.     {
  852.         wxStrncpy(buf, wxConvertMB2WX(uts.nodename), sz - 1);
  853.         buf[sz] = wxT('\0');
  854.     }
  855. #elif defined(HAVE_GETHOSTNAME)
  856.     bool ok = gethostname(buf, sz) != -1;
  857. #else // no uname, no gethostname
  858.     wxFAIL_MSG(wxT("don't know host name for this machine"));
  859.  
  860.     bool ok = FALSE;
  861. #endif // uname/gethostname
  862.  
  863.     if ( !ok )
  864.     {
  865.         wxLogSysError(_("Cannot get the hostname"));
  866.     }
  867.  
  868.     return ok;
  869. }
  870.  
  871. bool wxGetHostName(wxChar *buf, int sz)
  872. {
  873.     bool ok = wxGetHostNameInternal(buf, sz);
  874.  
  875.     if ( ok )
  876.     {
  877.         // BSD systems return the FQDN, we only want the hostname, so extract
  878.         // it (we consider that dots are domain separators)
  879.         wxChar *dot = wxStrchr(buf, wxT('.'));
  880.         if ( dot )
  881.         {
  882.             // nuke it
  883.             *dot = wxT('\0');
  884.         }
  885.     }
  886.  
  887.     return ok;
  888. }
  889.  
  890. bool wxGetFullHostName(wxChar *buf, int sz)
  891. {
  892.     bool ok = wxGetHostNameInternal(buf, sz);
  893.  
  894.     if ( ok )
  895.     {
  896.         if ( !wxStrchr(buf, wxT('.')) )
  897.         {
  898.             struct hostent *host = gethostbyname(wxConvertWX2MB(buf));
  899.             if ( !host )
  900.             {
  901.                 wxLogSysError(_("Cannot get the official hostname"));
  902.  
  903.                 ok = FALSE;
  904.             }
  905.             else
  906.             {
  907.                 // the canonical name
  908.                 wxStrncpy(buf, wxConvertMB2WX(host->h_name), sz);
  909.             }
  910.         }
  911.         //else: it's already a FQDN (BSD behaves this way)
  912.     }
  913.  
  914.     return ok;
  915. }
  916.  
  917. bool wxGetUserId(wxChar *buf, int sz)
  918. {
  919.     struct passwd *who;
  920.  
  921.     *buf = wxT('\0');
  922.     if ((who = getpwuid(getuid ())) != NULL)
  923.     {
  924.         wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
  925.         return TRUE;
  926.     }
  927.  
  928.     return FALSE;
  929. }
  930.  
  931. bool wxGetUserName(wxChar *buf, int sz)
  932. {
  933.     struct passwd *who;
  934.  
  935.     *buf = wxT('\0');
  936.     if ((who = getpwuid (getuid ())) != NULL)
  937.     {
  938.         // pw_gecos field in struct passwd is not standard
  939. #ifdef HAVE_PW_GECOS
  940.        char *comma = strchr(who->pw_gecos, ',');
  941.        if (comma)
  942.            *comma = '\0'; // cut off non-name comment fields
  943.        wxStrncpy (buf, wxConvertMB2WX(who->pw_gecos), sz - 1);
  944. #else // !HAVE_PW_GECOS
  945.        wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
  946. #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
  947.        return TRUE;
  948.     }
  949.  
  950.     return FALSE;
  951. }
  952.  
  953. #ifndef __WXMAC__
  954. wxString wxGetOsDescription()
  955. {
  956. #ifndef WXWIN_OS_DESCRIPTION
  957.     #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
  958. #else
  959.     return wxString::FromAscii( WXWIN_OS_DESCRIPTION );
  960. #endif
  961. }
  962. #endif
  963.  
  964. // this function returns the GUI toolkit version in GUI programs, but OS
  965. // version in non-GUI ones
  966. #if !wxUSE_GUI
  967.  
  968. int wxGetOsVersion(int *majorVsn, int *minorVsn)
  969. {
  970.     int major, minor;
  971.     char name[256];
  972.  
  973.     if ( sscanf(WXWIN_OS_DESCRIPTION, "%s %d.%d", name, &major, &minor) != 3 )
  974.     {
  975.         // unreckognized uname string format
  976.         major = minor = -1;
  977.     }
  978.  
  979.     if ( majorVsn )
  980.         *majorVsn = major;
  981.     if ( minorVsn )
  982.         *minorVsn = minor;
  983.  
  984.     return wxUNIX;
  985. }
  986.  
  987. #endif // !wxUSE_GUI
  988.  
  989. unsigned long wxGetProcessId()
  990. {
  991.     return (unsigned long)getpid();
  992. }
  993.  
  994. long wxGetFreeMemory()
  995. {
  996. #if defined(__LINUX__)
  997.     // get it from /proc/meminfo
  998.     FILE *fp = fopen("/proc/meminfo", "r");
  999.     if ( fp )
  1000.     {
  1001.         long memFree = -1;
  1002.  
  1003.         char buf[1024];
  1004.         if ( fgets(buf, WXSIZEOF(buf), fp) && fgets(buf, WXSIZEOF(buf), fp) )
  1005.         {
  1006.             long memTotal, memUsed;
  1007.             sscanf(buf, "Mem: %ld %ld %ld", &memTotal, &memUsed, &memFree);
  1008.         }
  1009.  
  1010.         fclose(fp);
  1011.  
  1012.         return memFree;
  1013.     }
  1014. #elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES)
  1015.     return sysconf(_SC_AVPHYS_PAGES)*sysconf(_SC_PAGESIZE);
  1016. //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
  1017. #endif
  1018.  
  1019.     // can't find it out
  1020.     return -1;
  1021. }
  1022.  
  1023. bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree)
  1024. {
  1025. #if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
  1026.     // the case to "char *" is needed for AIX 4.3
  1027.     wxStatFs fs;
  1028.     if ( statfs((char *)(const char*)path.fn_str(), &fs) != 0 )
  1029.     {
  1030.         wxLogSysError( wxT("Failed to get file system statistics") );
  1031.  
  1032.         return FALSE;
  1033.     }
  1034.  
  1035.     // under Solaris we also have to use f_frsize field instead of f_bsize
  1036.     // which is in general a multiple of f_frsize
  1037. #ifdef HAVE_STATVFS
  1038.     wxLongLong blockSize = fs.f_frsize;
  1039. #else // HAVE_STATFS
  1040.     wxLongLong blockSize = fs.f_bsize;
  1041. #endif // HAVE_STATVFS/HAVE_STATFS
  1042.  
  1043.     if ( pTotal )
  1044.     {
  1045.         *pTotal = wxLongLong(fs.f_blocks) * blockSize;
  1046.     }
  1047.  
  1048.     if ( pFree )
  1049.     {
  1050.         *pFree = wxLongLong(fs.f_bavail) * blockSize;
  1051.     }
  1052.  
  1053.     return TRUE;
  1054. #else // !HAVE_STATFS && !HAVE_STATVFS
  1055.     return FALSE;
  1056. #endif // HAVE_STATFS
  1057. }
  1058.  
  1059. // ----------------------------------------------------------------------------
  1060. // env vars
  1061. // ----------------------------------------------------------------------------
  1062.  
  1063. bool wxGetEnv(const wxString& var, wxString *value)
  1064. {
  1065.     // wxGetenv is defined as getenv()
  1066.     wxChar *p = wxGetenv(var);
  1067.     if ( !p )
  1068.         return FALSE;
  1069.  
  1070.     if ( value )
  1071.     {
  1072.         *value = p;
  1073.     }
  1074.  
  1075.     return TRUE;
  1076. }
  1077.  
  1078. bool wxSetEnv(const wxString& variable, const wxChar *value)
  1079. {
  1080. #if defined(HAVE_SETENV)
  1081.     return setenv(variable.mb_str(),
  1082.                   value ? (const char *)wxString(value).mb_str()
  1083.                         : NULL,
  1084.                   1 /* overwrite */) == 0;
  1085. #elif defined(HAVE_PUTENV)
  1086.     wxString s = variable;
  1087.     if ( value )
  1088.         s << _T('=') << value;
  1089.  
  1090.     // transform to ANSI
  1091.     const char *p = s.mb_str();
  1092.  
  1093.     // the string will be free()d by libc
  1094.     char *buf = (char *)malloc(strlen(p) + 1);
  1095.     strcpy(buf, p);
  1096.  
  1097.     return putenv(buf) == 0;
  1098. #else // no way to set an env var
  1099.     return FALSE;
  1100. #endif
  1101. }
  1102.  
  1103. // ----------------------------------------------------------------------------
  1104. // signal handling
  1105. // ----------------------------------------------------------------------------
  1106.  
  1107. #if wxUSE_ON_FATAL_EXCEPTION
  1108.  
  1109. #include <signal.h>
  1110.  
  1111. extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER)
  1112. {
  1113.     if ( wxTheApp )
  1114.     {
  1115.         // give the user a chance to do something special about this
  1116.         wxTheApp->OnFatalException();
  1117.     }
  1118.  
  1119.     abort();
  1120. }
  1121.  
  1122. bool wxHandleFatalExceptions(bool doit)
  1123. {
  1124.     // old sig handlers
  1125.     static bool s_savedHandlers = FALSE;
  1126.     static struct sigaction s_handlerFPE,
  1127.                             s_handlerILL,
  1128.                             s_handlerBUS,
  1129.                             s_handlerSEGV;
  1130.  
  1131.     bool ok = TRUE;
  1132.     if ( doit && !s_savedHandlers )
  1133.     {
  1134.         // install the signal handler
  1135.         struct sigaction act;
  1136.  
  1137.         // some systems extend it with non std fields, so zero everything
  1138.         memset(&act, 0, sizeof(act));
  1139.  
  1140.         act.sa_handler = wxFatalSignalHandler;
  1141.         sigemptyset(&act.sa_mask);
  1142.         act.sa_flags = 0;
  1143.  
  1144.         ok &= sigaction(SIGFPE, &act, &s_handlerFPE) == 0;
  1145.         ok &= sigaction(SIGILL, &act, &s_handlerILL) == 0;
  1146.         ok &= sigaction(SIGBUS, &act, &s_handlerBUS) == 0;
  1147.         ok &= sigaction(SIGSEGV, &act, &s_handlerSEGV) == 0;
  1148.         if ( !ok )
  1149.         {
  1150.             wxLogDebug(_T("Failed to install our signal handler."));
  1151.         }
  1152.  
  1153.         s_savedHandlers = TRUE;
  1154.     }
  1155.     else if ( s_savedHandlers )
  1156.     {
  1157.         // uninstall the signal handler
  1158.         ok &= sigaction(SIGFPE, &s_handlerFPE, NULL) == 0;
  1159.         ok &= sigaction(SIGILL, &s_handlerILL, NULL) == 0;
  1160.         ok &= sigaction(SIGBUS, &s_handlerBUS, NULL) == 0;
  1161.         ok &= sigaction(SIGSEGV, &s_handlerSEGV, NULL) == 0;
  1162.         if ( !ok )
  1163.         {
  1164.             wxLogDebug(_T("Failed to uninstall our signal handler."));
  1165.         }
  1166.  
  1167.         s_savedHandlers = FALSE;
  1168.     }
  1169.     //else: nothing to do
  1170.  
  1171.     return ok;
  1172. }
  1173.  
  1174. #endif // wxUSE_ON_FATAL_EXCEPTION
  1175.  
  1176. // ----------------------------------------------------------------------------
  1177. // error and debug output routines (deprecated, use wxLog)
  1178. // ----------------------------------------------------------------------------
  1179.  
  1180. #if WXWIN_COMPATIBILITY_2_2
  1181.  
  1182. void wxDebugMsg( const char *format, ... )
  1183. {
  1184.   va_list ap;
  1185.   va_start( ap, format );
  1186.   vfprintf( stderr, format, ap );
  1187.   fflush( stderr );
  1188.   va_end(ap);
  1189. }
  1190.  
  1191. void wxError( const wxString &msg, const wxString &title )
  1192. {
  1193.   wxFprintf( stderr, _("Error ") );
  1194.   if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
  1195.   if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
  1196.   wxFprintf( stderr, wxT(".\n") );
  1197. }
  1198.  
  1199. void wxFatalError( const wxString &msg, const wxString &title )
  1200. {
  1201.   wxFprintf( stderr, _("Error ") );
  1202.   if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
  1203.   if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
  1204.   wxFprintf( stderr, wxT(".\n") );
  1205.   exit(3); // the same exit code as for abort()
  1206. }
  1207.  
  1208. #endif // WXWIN_COMPATIBILITY_2_2
  1209.  
  1210.