]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/utilsunx.cpp
1. added range checks in wxGridStringTable
[wxWidgets.git] / src / unix / utilsunx.cpp
index c8bdafd3bf22583cde88aeace0ea7ddfa14621ba..fe4abae50e27af316e99f050b2c25c83515d964a 100644 (file)
 
 #include "wx/utils.h"
 #include "wx/process.h"
+#include "wx/thread.h"
 
-#include "wx/unix/execute.h"
+#include "wx/stream.h"
+
+#if wxUSE_GUI
+    #include "wx/unix/execute.h"
+#endif
 
 #include <stdarg.h>
 #include <dirent.h>
@@ -40,9 +45,7 @@
 #include <fcntl.h>          // for O_WRONLY and friends
 #include <time.h>           // nanosleep() and/or usleep()
 #include <ctype.h>          // isspace()
-
-// JACS: needed for FD_SETSIZE
-#include <sys/time.h>
+#include <sys/time.h>       // needed for FD_SETSIZE
 
 #ifdef HAVE_UNAME
     #include <sys/utsname.h> // for uname()
         #ifdef __SUN__
             int usleep(unsigned int usec);
         #else // !Sun
-        #ifdef __EMX__
-            /* I copied this from the XFree86 diffs. AV. */
-            #define INCL_DOSPROCESS
-            #include <os2.h>
-            void usleep(unsigned long delay)
-            {
-                DosSleep(delay ? (delay/1000l) : 1l);
-            }
-        #else
-            void usleep(unsigned long usec);
-        #endif
+            #ifdef __EMX__
+                /* I copied this from the XFree86 diffs. AV. */
+                #define INCL_DOSPROCESS
+                #include <os2.h>
+                inline void usleep(unsigned long delay)
+                {
+                    DosSleep(delay ? (delay/1000l) : 1l);
+                }
+            #else // !Sun && !EMX
+                void usleep(unsigned long usec);
+            #endif
         #endif // Sun/EMX/Something else
     };
-#define HAVE_USLEEP 1
+
+    #define HAVE_USLEEP 1
 #endif // Unices without usleep()
 
 // ============================================================================
@@ -95,14 +99,14 @@ void wxSleep(int nSecs)
 
 void wxUsleep(unsigned long milliseconds)
 {
-#ifdef HAVE_NANOSLEEP
+#if defined(HAVE_NANOSLEEP)
     timespec tmReq;
-    tmReq.tv_sec = milliseconds / 1000;
+    tmReq.tv_sec = (time_t)(milliseconds / 1000);
     tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
 
     // we're not interested in remaining time nor in return value
     (void)nanosleep(&tmReq, (timespec *)NULL);
-#elif defined( HAVE_USLEEP )
+#elif defined(HAVE_USLEEP)
     // uncomment this if you feel brave or if you are sure that your version
     // of Solaris has a safe usleep() function but please notice that usleep()
     // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
@@ -112,6 +116,9 @@ void wxUsleep(unsigned long milliseconds)
     #endif // Sun
 
     usleep(milliseconds * 1000); // usleep(3) wants microseconds
+#elif defined(HAVE_SLEEP)
+    // under BeOS sleep() takes seconds (what about other platforms, if any?)
+    sleep(milliseconds * 1000);
 #else // !sleep function
     #error "usleep() or nanosleep() function required for wxUsleep"
 #endif // sleep function
@@ -123,7 +130,7 @@ void wxUsleep(unsigned long milliseconds)
 
 int wxKill(long pid, wxSignal sig)
 {
-    return kill(pid, (int)sig);
+    return kill((pid_t)pid, (int)sig);
 }
 
 #define WXEXECUTE_NARGS   127
@@ -209,6 +216,8 @@ bool wxShell(const wxString& command)
     return wxExecute(cmd) != 0;
 }
 
+#if wxUSE_GUI
+
 void wxHandleProcessTermination(wxEndProcessData *proc_data)
 {
     int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid);
@@ -219,17 +228,19 @@ void wxHandleProcessTermination(wxEndProcessData *proc_data)
     int status = 0;
     int rc;
 
+    // wait for child termination and if waitpid() was interrupted, try again
     do
+    {
        rc = waitpid(pid, &status, 0);
-    while(rc == -1 && ( /* errno == ERESTARTSYS || */ errno == EINTR) );
-    // waitpid() was interrupted, try again
+    }
+    while ( rc == -1 && errno == EINTR );
+
 
-       
     if( rc == -1 || ! (WIFEXITED(status) || WIFSIGNALED(status)) )
     {
        wxLogSysError(_("Waiting for subprocess termination failed"));
        /* AFAIK, this can only happen if something went wrong within
-          wxGTK, i.e. due to a racecondition or some serious bug.
+          wxGTK, i.e. due to a race condition or some serious bug.
           After having fixed the order of statements in
           GTK_EndProcessDetector(). (KB)
        */
@@ -251,13 +262,100 @@ void wxHandleProcessTermination(wxEndProcessData *proc_data)
         {
            // wxExecute() will know about it
            proc_data->exitcode = status;
-           
+
            proc_data->pid = 0;
         }
     }
 }
 
-long wxExecute( wxChar **argv, bool sync, wxProcess *process )
+#endif // wxUSE_GUI
+
+#if wxUSE_GUI
+    #define WXUNUSED_UNLESS_GUI(p)  p
+#else
+    #define WXUNUSED_UNLESS_GUI(p)
+#endif
+
+// New wxStream classes to clean up the data when the process terminates
+
+#if wxUSE_GUI
+class wxProcessFileInputStream: public wxInputStream {
+ public:
+    wxProcessFileInputStream(int fd);
+    ~wxProcessFileInputStream();
+
+ protected: 
+    size_t OnSysRead(void *buffer, size_t bufsize);
+
+ protected:
+    int m_fd;
+};
+
+class wxProcessFileOutputStream: public wxOutputStream {
+ public:
+    wxProcessFileOutputStream(int fd);
+    ~wxProcessFileOutputStream();
+
+ protected:
+    size_t OnSysWrite(const void *buffer, size_t bufsize);
+
+ protected:
+    int m_fd;
+};
+
+wxProcessFileInputStream::wxProcessFileInputStream(int fd)
+{
+    m_fd = fd;
+}
+
+wxProcessFileInputStream::~wxProcessFileInputStream()
+{
+    close(m_fd);
+}
+
+size_t wxProcessFileInputStream::OnSysRead(void *buffer, size_t bufsize)
+{
+    int ret;
+
+    ret = read(m_fd, buffer, bufsize);
+    m_lasterror = wxSTREAM_NOERROR;
+    if (ret == 0)
+      m_lasterror = wxSTREAM_EOF;
+    if (ret == -1) {
+      m_lasterror = wxSTREAM_READ_ERROR;
+      ret = 0;
+    }
+    return ret;
+}
+
+wxProcessFileOutputStream::wxProcessFileOutputStream(int fd)
+{
+    m_fd = fd;
+}
+
+wxProcessFileOutputStream::~wxProcessFileOutputStream()
+{
+    close(m_fd);
+}
+
+size_t wxProcessFileOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
+{
+    int ret;
+
+    ret = write(m_fd, buffer, bufsize);
+    m_lasterror = wxSTREAM_NOERROR;
+    if (ret == -1) {
+      m_lasterror = wxSTREAM_WRITE_ERROR;
+      ret = 0;
+    }
+    return ret;
+}
+
+#endif
+      
+long wxExecute(wxChar **argv,
+               bool sync,
+               wxProcess * WXUNUSED_UNLESS_GUI(process))
 {
     wxCHECK_MSG( *argv, 0, wxT("can't exec empty command") );
 
@@ -297,6 +395,26 @@ long wxExecute( wxChar **argv, bool sync, wxProcess *process )
     }
 #endif // wxUSE_GUI
 
+#if wxUSE_GUI
+    int in_pipe[2] = { -1, -1 };
+    int out_pipe[2] = { -1, -1 };
+    // Only asynchronous mode is interresting
+    if (!sync && process && process->NeedPipe())
+    {
+        if (pipe(in_pipe) == -1 || pipe(out_pipe) == -1)
+        {
+            /* Free fds */
+            close(end_proc_detect[0]);
+            close(end_proc_detect[1]);
+            wxLogSysError( _("Pipe creation failed (Console pipes)") );
+
+            ARGS_CLEANUP;
+
+            return 0;
+        }
+    }
+#endif // wxUSE_GUI
+
     // fork the process
 #ifdef HAVE_VFORK
     pid_t pid = vfork();
@@ -305,6 +423,14 @@ long wxExecute( wxChar **argv, bool sync, wxProcess *process )
 #endif
     if (pid == -1)
     {
+#if wxUSE_GUI
+        close(end_proc_detect[0]);
+        close(end_proc_detect[1]);
+        close(in_pipe[0]);
+        close(in_pipe[1]);
+        close(out_pipe[0]);
+        close(out_pipe[1]);
+#endif
         wxLogSysError( _("Fork failed") );
 
         ARGS_CLEANUP;
@@ -328,7 +454,7 @@ long wxExecute( wxChar **argv, bool sync, wxProcess *process )
             for ( int fd = 0; fd < FD_SETSIZE; fd++ )
             {
 #if wxUSE_GUI
-                if ( fd == end_proc_detect[1] )
+                if ( fd == end_proc_detect[1] || fd == in_pipe[0] || fd == out_pipe[1] )
                     continue;
 #endif // wxUSE_GUI
 
@@ -337,6 +463,16 @@ long wxExecute( wxChar **argv, bool sync, wxProcess *process )
             }
         }
 
+        // Fake a console by duplicating pipes
+#if wxUSE_GUI
+        if (in_pipe[0] != -1) {
+            dup2(in_pipe[0], STDIN_FILENO);
+            dup2(out_pipe[1], STDOUT_FILENO);
+            close(in_pipe[0]);
+            close(out_pipe[1]);
+        }
+#endif // wxUSE_GUI
+
 #if 0
         close(STDERR_FILENO);
 
@@ -359,7 +495,6 @@ long wxExecute( wxChar **argv, bool sync, wxProcess *process )
 #if wxUSE_GUI
         wxEndProcessData *data = new wxEndProcessData;
 
-
         ARGS_CLEANUP;
 
         if ( sync )
@@ -368,8 +503,8 @@ long wxExecute( wxChar **argv, bool sync, wxProcess *process )
             data->process = NULL;
 
             // sync execution: indicate it by negating the pid
-            data->pid = -pid;
-            data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
+            data->pid      = -pid;
+            data->tag      = wxAddProcessCallback(data, end_proc_detect[0]);
             // we're in parent
             close(end_proc_detect[1]); // close writing side
 
@@ -385,12 +520,26 @@ long wxExecute( wxChar **argv, bool sync, wxProcess *process )
         }
         else
         {
+            // pipe initialization: construction of the wxStreams
+            if (process && process->NeedPipe()) {
+                // These two streams are relative to this process.
+                wxOutputStream *my_output_stream;
+                wxInputStream *my_input_stream;
+
+                my_output_stream = new wxProcessFileOutputStream(in_pipe[1]);
+                my_input_stream = new wxProcessFileInputStream(out_pipe[0]);
+                close(in_pipe[0]); // close reading side
+                close(out_pipe[1]); // close writing side
+
+                process->SetPipeStreams(my_input_stream, my_output_stream);
+            }
+
             // async execution, nothing special to do - caller will be
             // notified about the process termination if process != NULL, data
             // will be deleted in GTK_EndProcessDetector
-            data->process = process;
-            data->pid = pid;
-            data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
+            data->process  = process;
+            data->pid      = pid;
+            data->tag      = wxAddProcessCallback(data, end_proc_detect[0]);
             // we're in parent
             close(end_proc_detect[1]); // close writing side
 
@@ -562,24 +711,34 @@ bool wxGetUserId(wxChar *buf, int sz)
 bool wxGetUserName(wxChar *buf, int sz)
 {
     struct passwd *who;
-    char *comma;
 
     *buf = wxT('\0');
-    if ((who = getpwuid (getuid ())) != NULL) {
-#ifndef __VMS__
-       comma = strchr(who->pw_gecos, ',');
+    if ((who = getpwuid (getuid ())) != NULL)
+    {
+        // pw_gecos field in struct passwd is not standard
+#if HAVE_PW_GECOS
+       char *comma = strchr(who->pw_gecos, ',');
        if (comma)
            *comma = '\0'; // cut off non-name comment fields
        wxStrncpy (buf, wxConvertMB2WX(who->pw_gecos), sz - 1);
-#else
+#else // !HAVE_PW_GECOS
        wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
-#endif
+#endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
        return TRUE;
     }
 
     return FALSE;
 }
 
+wxString wxGetOsDescription()
+{
+#ifndef WXWIN_OS_DESCRIPTION
+    #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
+#else
+    return WXWIN_OS_DESCRIPTION;
+#endif
+}
+
 // ----------------------------------------------------------------------------
 // error and debug output routines (deprecated, use wxLog)
 // ----------------------------------------------------------------------------