#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>
#include <fcntl.h> // for O_WRONLY and friends
#include <time.h> // nanosleep() and/or usleep()
#include <ctype.h> // isspace()
+#include <sys/time.h> // needed for FD_SETSIZE
-// JACS: needed for FD_SETSIZE
-#include <sys/time.h>
-
-#if HAVE_UNAME
+#ifdef HAVE_UNAME
#include <sys/utsname.h> // for uname()
#endif // HAVE_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()
// ============================================================================
void wxUsleep(unsigned long milliseconds)
{
-#if 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 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
#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
int wxKill(long pid, wxSignal sig)
{
- return kill(pid, (int)sig);
+ return kill((pid_t)pid, (int)sig);
}
#define WXEXECUTE_NARGS 127
return wxExecute(cmd) != 0;
}
+#if wxUSE_GUI
+
void wxHandleProcessTermination(wxEndProcessData *proc_data)
{
int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid);
// systems wait() might be used instead in a loop (until the right pid
// terminates)
int status = 0;
- if ( waitpid(pid, &status, 0) == -1 || !WIFEXITED(status) )
+ int rc;
+
+ // wait for child termination and if waitpid() was interrupted, try again
+ do
+ {
+ rc = waitpid(pid, &status, 0);
+ }
+ while ( rc == -1 && errno == EINTR );
+
+
+ if( rc == -1 || ! (WIFEXITED(status) || WIFSIGNALED(status)) )
{
- wxLogSysError(_("Waiting for subprocess termination failed"));
+ wxLogSysError(_("Waiting for subprocess termination failed"));
+ /* AFAIK, this can only happen if something went wrong within
+ wxGTK, i.e. due to a race condition or some serious bug.
+ After having fixed the order of statements in
+ GTK_EndProcessDetector(). (KB)
+ */
}
else
{
proc_data->process->OnTerminate(proc_data->pid,
WEXITSTATUS(status));
}
+ // clean up
+ if ( proc_data->pid > 0 )
+ {
+ delete proc_data;
+ }
+ else
+ {
+ // wxExecute() will know about it
+ proc_data->exitcode = status;
+
+ proc_data->pid = 0;
+ }
}
+}
- // clean up
- if ( proc_data->pid > 0 )
- {
- delete proc_data;
+#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;
}
- else
- {
- // wxExecute() will know about it
- proc_data->exitcode = status;
+ return ret;
+}
+
+wxProcessFileOutputStream::wxProcessFileOutputStream(int fd)
+{
+ m_fd = fd;
+}
+
+wxProcessFileOutputStream::~wxProcessFileOutputStream()
+{
+ close(m_fd);
+}
- proc_data->pid = 0;
+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;
}
-long wxExecute( wxChar **argv, bool sync, wxProcess *process )
+#endif
+
+long wxExecute(wxChar **argv,
+ bool sync,
+ wxProcess * WXUNUSED_UNLESS_GUI(process))
{
wxCHECK_MSG( *argv, 0, wxT("can't exec empty command") );
// this macro will free memory we used above
#define ARGS_CLEANUP \
- for ( mb_argc = 0; mb_argb[mb_argc]; mb_argc++ ) \
+ for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
free(mb_argv[mb_argc])
#else // ANSI
// no need for cleanup
}
#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
-#if HAVE_VFORK
+#ifdef HAVE_VFORK
pid_t pid = vfork();
#else
pid_t pid = fork();
#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;
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
}
}
+ // 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);
else
{
#if wxUSE_GUI
- // we're in parent
- close(end_proc_detect[1]); // close writing side
-
wxEndProcessData *data = new wxEndProcessData;
- data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
ARGS_CLEANUP;
data->process = NULL;
// sync execution: indicate it by negating the pid
- data->pid = -pid;
+ data->pid = -pid;
+ data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
+ // we're in parent
+ close(end_proc_detect[1]); // close writing side
// it will be set to 0 from GTK_EndProcessDetector
while (data->pid != 0)
}
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 terminationif process != NULL, data
+ // notified about the process termination if process != NULL, data
// will be deleted in GTK_EndProcessDetector
- data->process = process;
- data->pid = pid;
+ 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
return pid;
}
return exitcode;
#endif // wxUSE_GUI
}
+ return 0;
#undef ARGS_CLEANUP
}
who = getpwnam (user.mb_str());
}
- return wxConvertMB2WX(who ? who->pw_dir : NULL);
+ return wxConvertMB2WX(who ? who->pw_dir : 0);
}
// ----------------------------------------------------------------------------
bool wxGetUserName(wxChar *buf, int sz)
{
struct passwd *who;
- char *comma;
*buf = wxT('\0');
- if ((who = getpwuid (getuid ())) != NULL) {
- 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 // !HAVE_PW_GECOS
+ wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
+#endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
return TRUE;
}
return FALSE;
}
-#if wxUSE_GUI
+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)
exit(3); // the same exit code as for abort()
}
-// ----------------------------------------------------------------------------
-// font-related functions
-// ----------------------------------------------------------------------------
-
-// define the functions to create and destroy native fonts for this toolkit
-#ifdef __X__
- static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
- {
- return XLoadQueryFont((Display *)wxGetDisplay(), fontSpec);
- }
-
- static inline void wxFreeFont(wxNativeFont font)
- {
- XFreeFont((Display *)wxGetDisplay(), font);
- }
-#elif defined(__WXGTK__)
-
- #include "gdk/gdk.h"
-
- static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
- {
- return gdk_font_load( wxConvertWX2MB(fontSpec) );
- }
-
- static inline void wxFreeFont(wxNativeFont font)
- {
- gdk_font_unref(font);
- }
-#else
- #error "Unknown GUI toolkit"
-#endif
-
-// returns TRUE if there are any fonts matching this font spec
-static bool wxTestFontSpec(const wxString& fontspec)
-{
- wxNativeFont test = wxLoadFont(fontspec);
- if ( test )
- {
- wxFreeFont(test);
-
- return TRUE;
- }
- else
- {
- return FALSE;
- }
-}
-
-// TODO encoding test logic should be moved to wxLoadQueryNearestFont()
-static wxNativeFont wxLoadQueryFont(int pointSize,
- int family,
- int style,
- int weight,
- bool WXUNUSED(underlined),
- const wxString &facename,
- wxFontEncoding encoding )
-{
- wxString xfamily;
- switch (family)
- {
- case wxDECORATIVE: xfamily = wxT("lucida"); break;
- case wxROMAN: xfamily = wxT("times"); break;
- case wxMODERN: xfamily = wxT("courier"); break;
- case wxSWISS: xfamily = wxT("helvetica"); break;
- case wxTELETYPE: xfamily = wxT("lucidatypewriter"); break;
- case wxSCRIPT: xfamily = wxT("utopia"); break;
- default: xfamily = wxT("*");
- }
-
- wxString fontSpec;
- if (!facename.IsEmpty())
- {
- fontSpec.Printf(wxT("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"),
- facename.c_str());
-
- if ( wxTestFontSpec(fontSpec) )
- {
- xfamily = facename;
- }
- //else: no such family, use default one instead
- }
-
- wxString xstyle;
- switch (style)
- {
- case wxITALIC: xstyle = wxT("i"); break;
- case wxSLANT: xstyle = wxT("o"); break;
- case wxNORMAL: xstyle = wxT("r"); break;
- default: xstyle = wxT("*"); break;
- }
-
- wxString xweight;
- switch (weight)
- {
- case wxBOLD:
- {
- fontSpec.Printf(wxT("-*-%s-bold-*-*-*-*-*-*-*-*-*-*-*"),
- xfamily.c_str());
- if ( wxTestFontSpec(fontSpec) )
- {
- xweight = wxT("bold");
- break;
- }
- fontSpec.Printf(wxT("-*-%s-heavy-*-*-*-*-*-*-*-*-*-*-*"),
- xfamily.c_str());
- if ( wxTestFontSpec(fontSpec) )
- {
- xweight = wxT("heavy");
- break;
- }
- fontSpec.Printf(wxT("-*-%s-extrabold-*-*-*-*-*-*-*-*-*-*-*"),
- xfamily.c_str());
- if ( wxTestFontSpec(fontSpec) )
- {
- xweight = wxT("extrabold");
- break;
- }
- fontSpec.Printf(wxT("-*-%s-demibold-*-*-*-*-*-*-*-*-*-*-*"),
- xfamily.c_str());
- if ( wxTestFontSpec(fontSpec) )
- {
- xweight = wxT("demibold");
- break;
- }
- fontSpec.Printf(wxT("-*-%s-black-*-*-*-*-*-*-*-*-*-*-*"),
- xfamily.c_str());
- if ( wxTestFontSpec(fontSpec) )
- {
- xweight = wxT("black");
- break;
- }
- fontSpec.Printf(wxT("-*-%s-ultrablack-*-*-*-*-*-*-*-*-*-*-*"),
- xfamily.c_str());
- if ( wxTestFontSpec(fontSpec) )
- {
- xweight = wxT("ultrablack");
- break;
- }
- }
- break;
- case wxLIGHT:
- {
- fontSpec.Printf(wxT("-*-%s-light-*-*-*-*-*-*-*-*-*-*-*"),
- xfamily.c_str());
- if ( wxTestFontSpec(fontSpec) )
- {
- xweight = wxT("light");
- break;
- }
- fontSpec.Printf(wxT("-*-%s-thin-*-*-*-*-*-*-*-*-*-*-*"),
- xfamily.c_str());
- if ( wxTestFontSpec(fontSpec) )
- {
- xweight = wxT("thin");
- break;
- }
- }
- break;
- case wxNORMAL:
- {
- fontSpec.Printf(wxT("-*-%s-medium-*-*-*-*-*-*-*-*-*-*-*"),
- xfamily.c_str());
- if ( wxTestFontSpec(fontSpec) )
- {
- xweight = wxT("medium");
- break;
- }
- fontSpec.Printf(wxT("-*-%s-normal-*-*-*-*-*-*-*-*-*-*-*"),
- xfamily.c_str());
- if ( wxTestFontSpec(fontSpec) )
- {
- xweight = wxT("normal");
- break;
- }
- fontSpec.Printf(wxT("-*-%s-regular-*-*-*-*-*-*-*-*-*-*-*"),
- xfamily.c_str());
- if ( wxTestFontSpec(fontSpec) )
- {
- xweight = wxT("regular");
- break;
- }
- xweight = wxT("*");
- }
- break;
- default: xweight = wxT("*"); break;
- }
-
- wxString xregistry, xencoding;
- if ( encoding == wxFONTENCODING_DEFAULT )
- {
- // use the apps default
- encoding = wxFont::GetDefaultEncoding();
- }
-
- bool test = TRUE; // should we test for availability of encoding?
- switch ( encoding )
- {
- case wxFONTENCODING_ISO8859_1:
- case wxFONTENCODING_ISO8859_2:
- case wxFONTENCODING_ISO8859_3:
- case wxFONTENCODING_ISO8859_4:
- case wxFONTENCODING_ISO8859_5:
- case wxFONTENCODING_ISO8859_6:
- case wxFONTENCODING_ISO8859_7:
- case wxFONTENCODING_ISO8859_8:
- case wxFONTENCODING_ISO8859_9:
- case wxFONTENCODING_ISO8859_10:
- case wxFONTENCODING_ISO8859_11:
- case wxFONTENCODING_ISO8859_13:
- case wxFONTENCODING_ISO8859_14:
- case wxFONTENCODING_ISO8859_15:
- {
- int cp = encoding - wxFONTENCODING_ISO8859_1 + 1;
- xregistry = wxT("iso8859");
- xencoding.Printf(wxT("%d"), cp);
- }
- break;
-
- case wxFONTENCODING_KOI8:
- xregistry = wxT("koi8");
- if ( wxTestFontSpec(wxT("-*-*-*-*-*-*-*-*-*-*-*-*-koi8-1")) )
- {
- xencoding = wxT("1");
-
- // test passed, no need to do it once more
- test = FALSE;
- }
- else
- {
- xencoding = wxT("*");
- }
- break;
-
- case wxFONTENCODING_CP1250:
- case wxFONTENCODING_CP1251:
- case wxFONTENCODING_CP1252:
- {
- int cp = encoding - wxFONTENCODING_CP1250 + 1250;
- fontSpec.Printf(wxT("-*-*-*-*-*-*-*-*-*-*-*-*-microsoft-cp%d"),
- cp);
- if ( wxTestFontSpec(fontSpec) )
- {
- xregistry = wxT("microsoft");
- xencoding.Printf(wxT("cp%d"), cp);
-
- // test passed, no need to do it once more
- test = FALSE;
- }
- else
- {
- // fall back to LatinX
- xregistry = wxT("iso8859");
- xencoding.Printf(wxT("%d"), cp - 1249);
- }
- }
- break;
-
- case wxFONTENCODING_SYSTEM:
- default:
- test = FALSE;
- xregistry =
- xencoding = wxT("*");
- }
-
- if ( test )
- {
- fontSpec.Printf(wxT("-*-*-*-*-*-*-*-*-*-*-*-*-%s-%s"),
- xregistry.c_str(), xencoding.c_str());
- if ( !wxTestFontSpec(fontSpec) )
- {
- // this encoding isn't available - what to do?
- xregistry =
- xencoding = wxT("*");
- }
- }
-
- // construct the X font spec from our data
- fontSpec.Printf(wxT("-*-%s-%s-%s-normal-*-*-%d-*-*-*-*-%s-%s"),
- xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
- pointSize, xregistry.c_str(), xencoding.c_str());
-
- return wxLoadFont(fontSpec);
-}
-
-wxNativeFont wxLoadQueryNearestFont(int pointSize,
- int family,
- int style,
- int weight,
- bool underlined,
- const wxString &facename,
- wxFontEncoding encoding)
-{
- wxNativeFont font = wxLoadQueryFont( pointSize, family, style, weight,
- underlined, facename, encoding );
-
- if (!font)
- {
- // search up and down by stepsize 10
- int max_size = pointSize + 20 * (1 + (pointSize/180));
- int min_size = pointSize - 20 * (1 + (pointSize/180));
-
- int i;
-
- // Search for smaller size (approx.)
- for ( i = pointSize - 10; !font && i >= 10 && i >= min_size; i -= 10 )
- {
- font = wxLoadQueryFont(i, family, style, weight, underlined,
- facename, encoding );
- }
-
- // Search for larger size (approx.)
- for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
- {
- font = wxLoadQueryFont( i, family, style, weight, underlined,
- facename, encoding );
- }
-
- // Try default family
- if ( !font && family != wxDEFAULT )
- {
- font = wxLoadQueryFont( pointSize, wxDEFAULT, style, weight,
- underlined, facename, encoding );
- }
-
- // Bogus font I
- if ( !font )
- {
- font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
- underlined, facename, encoding );
- }
-
- // Bogus font II
- if ( !font )
- {
- font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
- underlined, wxEmptyString, encoding );
- }
- }
-
- return font;
-}
-
-#endif // wxUSE_GUI