From a3c0d7684a8e960ddf90401b716b196695b94cfd Mon Sep 17 00:00:00 2001 From: Michael Wetherell Date: Thu, 18 Aug 2005 10:52:10 +0000 Subject: [PATCH] Implementations for some of the stubs git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@35221 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/msdos/utilsdos.cpp | 394 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 354 insertions(+), 40 deletions(-) diff --git a/src/msdos/utilsdos.cpp b/src/msdos/utilsdos.cpp index 81771cf700..ff98148001 100644 --- a/src/msdos/utilsdos.cpp +++ b/src/msdos/utilsdos.cpp @@ -1,9 +1,10 @@ ///////////////////////////////////////////////////////////////////////////// // Name: utils.cpp // Purpose: DOS implementations of utility functions -// Author: Vaclav Slavik +// Author: Vaclav Slavik, M.J.Wetherell // Id: $Id$ // Copyright: (c) 2001-2002 SciTech Software, Inc. (www.scitechsoft.com) +// (c) 2005 M.J.Wetherell // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -21,16 +22,24 @@ #include "wx/apptrait.h" #include "wx/log.h" #include "wx/process.h" +#include "wx/confbase.h" // for wxExpandEnvVars() +#include "wx/app.h" +#include "wx/cmdline.h" +#include "wx/filename.h" +#include "wx/wfstream.h" #include #include #include #include #include +#include #include +#include +#include //---------------------------------------------------------------------------- -// misc. +// Sleep //---------------------------------------------------------------------------- void wxSleep(int nSecs) @@ -47,7 +56,14 @@ void wxMilliSleep(unsigned long milliseconds) #else clock_t start = clock(); while ((clock() - start) * 1000 / CLOCKS_PER_SEC < (clock_t)milliseconds) - ; // FIXME: need to yield here + { + // yield if in a multitasking environment + // "Release Current Virtual Machine's Time Slice" in DPMI 1.0 + REGS r; + memset(&r, 0, sizeof(r)); + r.x.ax = 0x1680; + int386(0x2f, &r, &r); + } #endif } @@ -60,11 +76,9 @@ void wxMicroSleep(unsigned long microseconds) #endif } -// Get Process ID -unsigned long wxGetProcessId() -{ - return (unsigned long)getpid(); -} +//---------------------------------------------------------------------------- +// Get/Set environment variables +//---------------------------------------------------------------------------- bool wxGetEnv(const wxString& var, wxString *value) { @@ -95,21 +109,102 @@ bool wxSetEnv(const wxString& variable, const wxChar *value) return putenv(buf) == 0; } +//---------------------------------------------------------------------------- +// Hostname, username, home directory +//---------------------------------------------------------------------------- + +// Based on the MSW implementation +// +// Respects the following environment variables in this order: %HomeDrive% + +// %HomePath%, %UserProfile%, $HOME. Otherwise takes program's directory if +// wxApp has been initialised, otherwise returns ".". +// const wxChar* wxGetHomeDir(wxString *home) { - *home = wxT("."); - return home->c_str(); + wxString& strDir = *home; + + strDir.clear(); + + // try HOMEDRIVE/PATH + const wxChar *szHome = wxGetenv(wxT("HOMEDRIVE")); + if ( szHome != NULL ) + strDir << szHome; + szHome = wxGetenv(wxT("HOMEPATH")); + + if ( szHome != NULL ) + { + strDir << szHome; + + // the idea is that under NT these variables have default values of + // "%systemdrive%:" and "\\". As we don't want to create our config + // files in the root directory of the system drive, we will create it + // in our program's dir. However, if the user took care to set + // HOMEPATH to something other than "\\", we suppose that he knows + // what he is doing and use the supplied value. + if ( wxStrcmp(szHome, wxT("\\")) == 0 ) + strDir.clear(); + } + + if ( strDir.empty() ) + { + // If we have a valid USERPROFILE directory, as is the case in + // Windows NT, 2000 and XP, we should use that as our home directory. + szHome = wxGetenv(wxT("USERPROFILE")); + + if ( szHome != NULL ) + strDir = szHome; + } + + if ( strDir.empty() ) + { + // If we have a valid HOME directory, as is used on many machines + // that have unix utilities on them, we should use that. + szHome = wxGetenv(wxT("HOME")); + + if ( szHome != NULL ) + { + strDir = szHome; + // when msys sets %HOME% it uses '/' (cygwin uses '\\') + strDir.Replace(_T("/"), _T("\\")); + } + } + + if ( !strDir.empty() ) + { + // sometimes the value of HOME may be "%USERPROFILE%", so reexpand the + // value once again, it shouldn't hurt anyhow + strDir = wxExpandEnvVars(strDir); + } + else // fall back to the program directory + { + if ( wxTheApp ) + { + wxString prog(wxTheApp->argv[0]); +#ifdef __DJGPP__ + // djgpp startup code switches the slashes around, so restore them + prog.Replace(_T("/"), _T("\\")); +#endif + // it needs to be a full path to be usable + if ( prog.compare(1, 2, _T(":\\")) == 0 ) + wxSplitPath(prog, &strDir, NULL, NULL); + } + if ( strDir.empty() ) + { + strDir = _T("."); + } + } + + return strDir.c_str(); } -const wxChar* wxGetUserHomeDir(wxString *home) +wxChar *wxGetUserHome(const wxString& user) { - *home = wxT("."); - return home->c_str(); -} + static wxString home; -wxChar *wxGetUserHome(const wxString &user) -{ - return wxT("."); + if (user.empty() || user == wxGetUserId()) + return wx_const_cast(wxChar*, wxGetHomeDir(&home)); + else + return _T(""); } #if WXWIN_COMPATIBILITY_2_2 @@ -123,53 +218,272 @@ void wxFatalError(const wxString &msg, const wxString &title) } #endif // WXWIN_COMPATIBILITY_2_2 -bool wxGetUserId(wxChar *WXUNUSED(buf), int WXUNUSED(sz)) +// returns %UserName%, $USER or just "user" +// +bool wxGetUserId(wxChar *buf, int n) { - wxFAIL_MSG( wxT("wxGetUserId not implemented under MS-DOS!") ); - return FALSE; + const wxChar *user = wxGetenv(_T("UserName")); + + if (!user) + user = wxGetenv(_T("USER")); + + if (!user) + user = _T("user"); + + wxStrncpy(buf, user, n); + return true; } -bool wxGetUserName(wxChar *WXUNUSED(buf), int WXUNUSED(sz)) +bool wxGetUserName(wxChar *buf, int n) { - wxFAIL_MSG( wxT("wxGetUserName not implemented under MS-DOS!") ); - return FALSE; + return wxGetUserId(buf, n); } -bool wxGetHostName(wxChar *WXUNUSED(buf), int WXUNUSED(sz)) +// returns %ComputerName%, or $HOSTNAME, or "host" +// +bool wxGetHostName(wxChar *buf, int n) { - wxFAIL_MSG( wxT("wxGetHostName not implemented under MS-DOS!") ); - return FALSE; + const wxChar *host = wxGetenv(_T("ComputerName")); + + if (!host) + host = wxGetenv(_T("HOSTNAME")); + + if (!host) + host = _T("host"); + + wxStrncpy(buf, host, n); + return true; } -bool wxGetFullHostName(wxChar *WXUNUSED(buf), int WXUNUSED(sz)) +// adds %UserDnsDomain% to wxGetHostName() +// +bool wxGetFullHostName(wxChar *buf, int n) { - wxFAIL_MSG( wxT("wxGetFullHostName not implemented under MS-DOS!") ); - return FALSE; + wxGetHostName(buf, n); + + const wxChar *domain = wxGetenv(_T("UserDnsDomain")); + + if (domain) + wxStrncat(wxStrncat(buf, _T("."), n), domain, n); + + return true; } -int wxKill(long WXUNUSED(pid), wxSignal WXUNUSED(sig), wxKillError *WXUNUSED(rc), int WXUNUSED(flags)) +//---------------------------------------------------------------------------- +// Processes +//---------------------------------------------------------------------------- + +unsigned long wxGetProcessId() { - wxFAIL_MSG( wxT("wxKill not implemented under MS-DOS!") ); - return 0; + return (unsigned long)getpid(); } -long wxExecute(const wxString& WXUNUSED(command), int WXUNUSED(flags), wxProcess *WXUNUSED(process)) +int wxKill(long pid, wxSignal sig, wxKillError *rc, int WXUNUSED(flags)) { - wxFAIL_MSG( wxT("wxExecute not implemented under MS-DOS!") ); - return 0; + int result = -1; + + if (pid != (long)wxGetProcessId()) + { + result = raise(sig); + if (rc) + *rc = result == 0 ? wxKILL_OK : wxKILL_BAD_SIGNAL; + } + else + { + wxLogDebug(_T("wxKill can only send signals to the current process under MSDOS")); + if (rc) + *rc = wxKILL_NO_PROCESS; + } + + return result; } -long wxExecute(char **WXUNUSED(argv), int WXUNUSED(flags), wxProcess *WXUNUSED(process)) +bool wxShell(const wxString& command /*=wxEmptyString*/) { - wxFAIL_MSG( wxT("wxExecute not implemented under MS-DOS!") ); - return 0; + // FIXME: suspend/resume gui + int result = system(command); + + if (result == -1) + wxLogSysError(_("can't execute '%s'"), command.c_str()); + + return result == 0; } +long wxExecute(const wxString& command, int flags, wxProcess *process) +{ + // FIXME: shouldn't depend on wxCmdLineParser + wxArrayString args(wxCmdLineParser::ConvertStringToArgs(command)); + size_t n = args.size(); + wxChar **argv = new wxChar*[n + 1]; + + argv[n] = NULL; + while (n-- > 0) + argv[n] = wx_const_cast(wxChar*, args[n].c_str()); + + long result = wxExecute(argv, flags, process); + + delete [] argv; + return result; +} + +#if wxUSE_STREAMS + +// A wxFFileInputStream that deletes the file in it's destructor +// +class wxTempFileInStream : public wxFFileInputStream +{ +public: + wxTempFileInStream(const wxString& name) + : wxFFileInputStream(name, _T("rt")) + { } + + ~wxTempFileInStream() + { + m_file->Close(); + wxRemoveFile(m_file->GetName()); + } +}; + +// A file descriptor that can be redirected to a file +// +class wxRedirectableFd +{ +public: + wxRedirectableFd(int fd) : m_fd(fd), m_dup(-1) { } + ~wxRedirectableFd(); + + // Redirect the descriptor to a file, similar to ANSI C's freopen, but + // for low level descriptors. The desctructor un-redirects. If O_CREAT + // is in the flags then the destructor will delete the file unless it is + // given away with Release(). + bool Reopen(const wxString& name, int flags); + + // un-redirect the redirected file descriptor, closing the file, and give + // away the filename without deleting it + wxString Release(); + +private: + // un-redirect the descriptor, closing the file + void Restore(); + + int m_fd; + int m_dup; + wxString m_name; +}; + +wxRedirectableFd::~wxRedirectableFd() +{ + Restore(); + if (!m_name.empty()) + wxRemoveFile(m_name); +} + +bool wxRedirectableFd::Reopen(const wxString& name, int flags) +{ + wxASSERT(m_dup == -1); + bool result = false; + + // save a duplicate so that the descriptor can be closed now and + // restored later + m_dup = dup(m_fd); + + if (m_dup != -1) + { + int tmp = open(name.mb_str(), flags); + + if (tmp != -1) + { + close(m_fd); + + if (flags & O_CREAT) + m_name = name; + + result = dup2(tmp, m_fd) == m_fd; + close(tmp); + } + } + + if (!result) + wxLogSysError(_("error opening '%s'"), name.c_str()); + + return result; +} + +void wxRedirectableFd::Restore() +{ + if (m_dup != -1) + { + close(m_fd); + dup2(m_dup, m_fd); + close(m_dup); + m_dup = -1; + } +} + +wxString wxRedirectableFd::Release() +{ + Restore(); + wxString name = m_name; + m_name.clear(); + return name; +} + +#endif // wxUSE_STREAMS + +// wxExecute implementation +// +long wxExecute(wxChar **argv, int flags, wxProcess *process) +{ +#if wxUSE_STREAMS + const int STDIN = 0; + const int STDOUT = 1; + const int STDERR = 2; + + wxRedirectableFd in(STDIN), out(STDOUT), err(STDERR); + bool redirect = process && process->IsRedirected() && (flags & wxEXEC_SYNC); + + if (redirect) + { + // close stdin/out/err and reopen them as files + if (!in.Reopen(_T("NUL"), O_RDONLY | O_TEXT)) + return -1; + + if (!out.Reopen(wxFileName::CreateTempFileName(_T("out")), + O_CREAT | O_WRONLY | O_TRUNC | O_TEXT)) + return -1; + + if (!err.Reopen(wxFileName::CreateTempFileName(_T("err")), + O_CREAT | O_WRONLY | O_TRUNC | O_TEXT)) + return -1; + } +#endif // wxUSE_STREAMS + + // FIXME: suspend/resume gui + int mode = flags & wxEXEC_SYNC ? P_WAIT : P_NOWAIT; + int result = spawnvp(mode, argv[0], argv); + + if (result == -1) + wxLogSysError(_("can't execute '%s'"), argv[0]); + +#if wxUSE_STREAMS + if (redirect) + process->SetPipeStreams(new wxTempFileInStream(out.Release()), + new wxFFileOutputStream(_T("NUL"), _T("wt")), + new wxTempFileInStream(err.Release())); +#endif // wxUSE_STREAMS + + return result; +} + +//---------------------------------------------------------------------------- +// Traits for console apps +//---------------------------------------------------------------------------- + wxToolkitInfo& wxConsoleAppTraits::GetToolkitInfo() { static wxToolkitInfo info; - info.versionMajor = -1; // FIXME - info.versionMinor = -1; + info.versionMajor = _osmajor; + info.versionMinor = _osminor; info.name = _T("wxBase"); info.os = wxDOS; return info;