]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msdos/utilsdos.cpp
Use wxCONTROL_SPECIAL to denote first header button
[wxWidgets.git] / src / msdos / utilsdos.cpp
index 81771cf70088ab6a9fc166477ee14ef5ca0457a4..d5c8a1a0fe2cb0357431f3f69dcd48b76d27b802 100644 (file)
@@ -1,9 +1,10 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        utils.cpp
+// Name:        src/msdos/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
 /////////////////////////////////////////////////////////////////////////////
 
 #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 <stdarg.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <signal.h>
 #include <time.h>
+#include <dos.h>
+#include <process.h>
 
 //----------------------------------------------------------------------------
-// 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,26 +79,24 @@ 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 )
@@ -95,82 +112,395 @@ 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(_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 )
+                wxFileName::SplitPath(prog, &strDir, NULL, NULL);
+        }
+        if ( strDir.empty() )
+        {
+            strDir = _T(".");
+        }
+    }
+
+    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(_T("UserName"));
+
+    if (!user)
+        user = wxGetenv(_T("USER"));
+
+    if (!user)
+        user = _T("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(_T("ComputerName"));
+
+    if (!host)
+        host = wxGetenv(_T("HOSTNAME"));
+
+    if (!host)
+        host = _T("host");
+
+    wxStrlcpy(buf, host, n);
+    return true;
+}
+
+// adds %UserDnsDomain% to wxGetHostName()
+//
+bool wxGetFullHostName(wxChar *buf, int n)
+{
+    wxGetHostName(buf, n);
+
+    const wxChar *domain = wxGetenv(_T("UserDnsDomain"));
+
+    if (domain)
+        wxStrncat(wxStrncat(buf, _T("."), 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(_T("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)
 {
-    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<wxChar*>((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, _T("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)
 {
-    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(_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;
+}
+
+
+//----------------------------------------------------------------------------
+// OS-related
+//----------------------------------------------------------------------------
+
+wxString wxGetOsDescription()
+{
+    wxString osname(_T("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;
 }
+