X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/81d9e625564a18de11df7270b689e6e5ae6c2e58..7198c3368055d88249a338eb33b21f051f674806:/src/msdos/utilsdos.cpp diff --git a/src/msdos/utilsdos.cpp b/src/msdos/utilsdos.cpp index 81771cf700..52bfea46da 100644 --- a/src/msdos/utilsdos.cpp +++ b/src/msdos/utilsdos.cpp @@ -1,9 +1,10 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: utils.cpp +// Name: src/msdos/utilsdos.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 ///////////////////////////////////////////////////////////////////////////// @@ -15,22 +16,33 @@ #endif #include "wx/utils.h" -#include "wx/string.h" -#include "wx/intl.h" +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/app.h" +#endif + #include "wx/apptrait.h" -#include "wx/log.h" #include "wx/process.h" +#include "wx/confbase.h" // for wxExpandEnvVars() +#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 +59,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,30 +79,28 @@ 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) { // wxGetenv is defined as getenv() wxChar *p = wxGetenv(var); if ( !p ) - return FALSE; + return false; if ( value ) *value = p; - return TRUE; + return true; } -bool wxSetEnv(const wxString& variable, const wxChar *value) +static bool wxDoSetEnv(const wxString& variable, const char *value) { wxString s = variable; if ( value ) - s << _T('=') << value; + s << wxT('=') << value; // transform to ANSI const char *p = s.mb_str(); @@ -95,82 +112,403 @@ bool wxSetEnv(const wxString& variable, const wxChar *value) return putenv(buf) == 0; } +bool wxSetEnv(const wxString& variable, const wxString& value) +{ + return wxDoSetEnv(variable, value.mb_str()); +} + +bool wxUnsetEnv(const wxString& variable) +{ + return wxDoSetEnv(variable, NULL); +} + + +//---------------------------------------------------------------------------- +// 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(wxT("/"), wxT("\\")); + } + } + + 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(wxT("/"), wxT("\\")); +#endif + // it needs to be a full path to be usable + if ( prog.compare(1, 2, wxT(":\\")) == 0 ) + wxFileName::SplitPath(prog, &strDir, NULL, NULL); + } + if ( strDir.empty() ) + { + strDir = wxT("."); + } + } + + return strDir.c_str(); +} + +wxString wxGetUserHome(const wxString& user) +{ + wxString home; + + if (user.empty() || user == wxGetUserId()) + wxGetHomeDir(&home); + + return home; +} + +// returns %UserName%, $USER or just "user" +// +bool wxGetUserId(wxChar *buf, int n) +{ + const wxChar *user = wxGetenv(wxT("UserName")); + + if (!user) + user = wxGetenv(wxT("USER")); + + if (!user) + user = wxT("user"); + + wxStrlcpy(buf, user, n); + return true; +} + +bool wxGetUserName(wxChar *buf, int n) +{ + return wxGetUserId(buf, n); +} + +// returns %ComputerName%, or $HOSTNAME, or "host" +// +bool wxGetHostName(wxChar *buf, int n) +{ + const wxChar *host = wxGetenv(wxT("ComputerName")); + + if (!host) + host = wxGetenv(wxT("HOSTNAME")); + + if (!host) + host = wxT("host"); + + wxStrlcpy(buf, host, n); + return true; +} + +// adds %UserDnsDomain% to wxGetHostName() +// +bool wxGetFullHostName(wxChar *buf, int n) +{ + wxGetHostName(buf, n); + + const wxChar *domain = wxGetenv(wxT("UserDnsDomain")); + + if (domain) + wxStrncat(wxStrncat(buf, wxT("."), n), domain, n); + + return true; } -const wxChar* wxGetUserHomeDir(wxString *home) +//---------------------------------------------------------------------------- +// Processes +//---------------------------------------------------------------------------- + +unsigned long wxGetProcessId() { - *home = wxT("."); - return home->c_str(); + return (unsigned long)getpid(); } -wxChar *wxGetUserHome(const wxString &user) +int wxKill(long pid, wxSignal sig, wxKillError *rc, int WXUNUSED(flags)) { - return wxT("."); + int result = -1; + + if (pid != (long)wxGetProcessId()) + { + result = raise(sig); + if (rc) + *rc = result == 0 ? wxKILL_OK : wxKILL_BAD_SIGNAL; + } + else + { + wxLogDebug(wxT("wxKill can only send signals to the current process under MSDOS")); + if (rc) + *rc = wxKILL_NO_PROCESS; + } + + return result; } -#if WXWIN_COMPATIBILITY_2_2 -void wxFatalError(const wxString &msg, const wxString &title) +bool wxShell(const wxString& command /*=wxEmptyString*/) { - wxFprintf( stderr, _("Error ") ); - if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) ); - if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) ); - wxFprintf( stderr, wxT(".\n") ); - exit(3); // the same exit code as for abort() + // FIXME: suspend/resume gui + int result = system(command); + + if (result == -1) + { + wxLogSysError(_("can't execute '%s'"), command.c_str()); + } + + return result == 0; } -#endif // WXWIN_COMPATIBILITY_2_2 -bool wxGetUserId(wxChar *WXUNUSED(buf), int WXUNUSED(sz)) +long wxExecute(const wxString& command, int flags, wxProcess *process, + const wxExecuteEnv *env) { - wxFAIL_MSG( wxT("wxGetUserId not implemented under MS-DOS!") ); - return FALSE; + // 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] = const_cast((const char *)args[n].c_str()); + + long result = wxExecute(argv, flags, process); + + delete [] argv; + return result; } -bool wxGetUserName(wxChar *WXUNUSED(buf), int WXUNUSED(sz)) +#if wxUSE_STREAMS + +// A wxFFileInputStream that deletes the file in it's destructor +// +class wxTempFileInStream : public wxFFileInputStream +{ +public: + wxTempFileInStream(const wxString& name) + : wxFFileInputStream(name, wxT("rt")) + { } + + virtual ~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() { - wxFAIL_MSG( wxT("wxGetUserName not implemented under MS-DOS!") ); - return FALSE; + Restore(); + if (!m_name.empty()) + wxRemoveFile(m_name); } -bool wxGetHostName(wxChar *WXUNUSED(buf), int WXUNUSED(sz)) +bool wxRedirectableFd::Reopen(const wxString& name, int flags) { - wxFAIL_MSG( wxT("wxGetHostName not implemented under MS-DOS!") ); - return FALSE; + 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; } -bool wxGetFullHostName(wxChar *WXUNUSED(buf), int WXUNUSED(sz)) +void wxRedirectableFd::Restore() { - wxFAIL_MSG( wxT("wxGetFullHostName not implemented under MS-DOS!") ); - return FALSE; + if (m_dup != -1) + { + close(m_fd); + dup2(m_dup, m_fd); + close(m_dup); + m_dup = -1; + } } -int wxKill(long WXUNUSED(pid), wxSignal WXUNUSED(sig), wxKillError *WXUNUSED(rc), int WXUNUSED(flags)) +wxString wxRedirectableFd::Release() { - wxFAIL_MSG( wxT("wxKill not implemented under MS-DOS!") ); - return 0; + Restore(); + wxString name = m_name; + m_name.clear(); + return name; } -long wxExecute(const wxString& WXUNUSED(command), int WXUNUSED(flags), wxProcess *WXUNUSED(process)) +#endif // wxUSE_STREAMS + +// wxExecute implementation +// +long wxExecute(wxChar **argv, int flags, wxProcess *process, + const wxString* cwd, const wxEnvVariableHashMap* env) { - wxFAIL_MSG( wxT("wxExecute not implemented under MS-DOS!") ); - return 0; +#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(wxT("NUL"), O_RDONLY | O_TEXT)) + return -1; + + if (!out.Reopen(wxFileName::CreateTempFileName(wxT("out")), + O_CREAT | O_WRONLY | O_TRUNC | O_TEXT)) + return -1; + + if (!err.Reopen(wxFileName::CreateTempFileName(wxT("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(wxT("NUL"), wxT("wt")), + new wxTempFileInStream(err.Release())); +#endif // wxUSE_STREAMS + + return result; +} + + +//---------------------------------------------------------------------------- +// OS-related +//---------------------------------------------------------------------------- + +wxString wxGetOsDescription() +{ + wxString osname(wxT("DOS")); + return osname; } -long wxExecute(char **WXUNUSED(argv), int WXUNUSED(flags), wxProcess *WXUNUSED(process)) +wxOperatingSystemId wxGetOsVersion(int *verMaj, int *verMin) { - wxFAIL_MSG( wxT("wxExecute not implemented under MS-DOS!") ); - return 0; + if ( verMaj ) + *verMaj = _osmajor; + if ( verMin ) + *verMin = _osminor; + + return wxOS_DOS; } -wxToolkitInfo& wxConsoleAppTraits::GetToolkitInfo() +bool wxIsPlatform64Bit() { - static wxToolkitInfo info; - info.versionMajor = -1; // FIXME - info.versionMinor = -1; - info.name = _T("wxBase"); - info.os = wxDOS; - return info; + return false; } +