]> git.saurik.com Git - wxWidgets.git/blob - src/msdos/utilsdos.cpp
code cleanup in DrawTextRectangle()
[wxWidgets.git] / src / msdos / utilsdos.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msdos/utils.cpp
3 // Purpose:     DOS implementations of utility functions
4 // Author:      Vaclav Slavik, M.J.Wetherell
5 // Id:          $Id$
6 // Copyright:   (c) 2001-2002 SciTech Software, Inc. (www.scitechsoft.com)
7 //              (c) 2005 M.J.Wetherell
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15     #pragma hdrstop
16 #endif
17
18 #include "wx/utils.h"
19
20 #ifndef WX_PRECOMP
21     #include "wx/string.h"
22     #include "wx/intl.h"
23     #include "wx/log.h"
24     #include "wx/app.h"
25 #endif
26
27 #include "wx/apptrait.h"
28 #include "wx/process.h"
29 #include "wx/confbase.h"        // for wxExpandEnvVars()
30 #include "wx/cmdline.h"
31 #include "wx/filename.h"
32 #include "wx/wfstream.h"
33
34 #include <stdarg.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39 #include <signal.h>
40 #include <time.h>
41 #include <dos.h>
42 #include <process.h>
43
44 //----------------------------------------------------------------------------
45 // Sleep
46 //----------------------------------------------------------------------------
47
48 void wxSleep(int nSecs)
49 {
50     wxMilliSleep(1000 * nSecs);
51 }
52
53 void wxMilliSleep(unsigned long milliseconds)
54 {
55 #if HAVE_USLEEP || defined __DJGPP__
56     usleep(milliseconds * 1000);
57 #elif defined __WATCOMC__
58     delay(milliseconds);
59 #else
60     clock_t start = clock();
61     while ((clock() - start) * 1000 / CLOCKS_PER_SEC < (clock_t)milliseconds)
62     {
63         // yield if in a multitasking environment
64         // "Release Current Virtual Machine's Time Slice" in DPMI 1.0
65         REGS r;
66         memset(&r, 0, sizeof(r));
67         r.x.ax = 0x1680;
68         int386(0x2f, &r, &r);
69     }
70 #endif
71 }
72
73 void wxMicroSleep(unsigned long microseconds)
74 {
75 #if HAVE_USLEEP || defined __DJGPP__
76     usleep(microseconds);
77 #else
78     wxMilliSleep(microseconds/1000);
79 #endif
80 }
81
82 //----------------------------------------------------------------------------
83 // Get/Set environment variables
84 //----------------------------------------------------------------------------
85
86 bool wxGetEnv(const wxString& var, wxString *value)
87 {
88     // wxGetenv is defined as getenv()
89     wxChar *p = wxGetenv(var);
90     if ( !p )
91         return false;
92
93     if ( value )
94         *value = p;
95
96     return true;
97 }
98
99 bool wxSetEnv(const wxString& variable, const wxChar *value)
100 {
101     wxString s = variable;
102     if ( value )
103         s << _T('=') << value;
104
105     // transform to ANSI
106     const char *p = s.mb_str();
107
108     // the string will be free()d by libc
109     char *buf = (char *)malloc(strlen(p) + 1);
110     strcpy(buf, p);
111
112     return putenv(buf) == 0;
113 }
114
115 //----------------------------------------------------------------------------
116 // Hostname, username, home directory
117 //----------------------------------------------------------------------------
118
119 // Based on the MSW implementation
120 //
121 // Respects the following environment variables in this order: %HomeDrive% +
122 // %HomePath%, %UserProfile%, $HOME. Otherwise takes program's directory if
123 // wxApp has been initialised, otherwise returns ".".
124 //
125 const wxChar* wxGetHomeDir(wxString *home)
126 {
127     wxString& strDir = *home;
128
129     strDir.clear();
130
131     // try HOMEDRIVE/PATH
132     const wxChar *szHome = wxGetenv(wxT("HOMEDRIVE"));
133     if ( szHome != NULL )
134         strDir << szHome;
135     szHome = wxGetenv(wxT("HOMEPATH"));
136
137     if ( szHome != NULL )
138     {
139         strDir << szHome;
140
141         // the idea is that under NT these variables have default values of
142         // "%systemdrive%:" and "\\". As we don't want to create our config
143         // files in the root directory of the system drive, we will create it
144         // in our program's dir. However, if the user took care to set
145         // HOMEPATH to something other than "\\", we suppose that he knows
146         // what he is doing and use the supplied value.
147         if ( wxStrcmp(szHome, wxT("\\")) == 0 )
148             strDir.clear();
149     }
150
151     if ( strDir.empty() )
152     {
153         // If we have a valid USERPROFILE directory, as is the case in
154         // Windows NT, 2000 and XP, we should use that as our home directory.
155         szHome = wxGetenv(wxT("USERPROFILE"));
156
157         if ( szHome != NULL )
158             strDir = szHome;
159     }
160
161     if ( strDir.empty() )
162     {
163         // If we have a valid HOME directory, as is used on many machines
164         // that have unix utilities on them, we should use that.
165         szHome = wxGetenv(wxT("HOME"));
166
167         if ( szHome != NULL )
168         {
169             strDir = szHome;
170             // when msys sets %HOME% it uses '/' (cygwin uses '\\')
171             strDir.Replace(_T("/"), _T("\\"));
172         }
173     }
174
175     if ( !strDir.empty() )
176     {
177         // sometimes the value of HOME may be "%USERPROFILE%", so reexpand the
178         // value once again, it shouldn't hurt anyhow
179         strDir = wxExpandEnvVars(strDir);
180     }
181     else // fall back to the program directory
182     {
183         if ( wxTheApp )
184         {
185             wxString prog(wxTheApp->argv[0]);
186 #ifdef __DJGPP__
187             // djgpp startup code switches the slashes around, so restore them
188             prog.Replace(_T("/"), _T("\\"));
189 #endif
190             // it needs to be a full path to be usable
191             if ( prog.compare(1, 2, _T(":\\")) == 0 )
192                 wxSplitPath(prog, &strDir, NULL, NULL);
193         }
194         if ( strDir.empty() )
195         {
196             strDir = _T(".");
197         }
198     }
199
200     return strDir.c_str();
201 }
202
203 wxChar *wxGetUserHome(const wxString& user)
204 {
205     static wxString home;
206
207     if (user.empty() || user == wxGetUserId())
208         return wx_const_cast(wxChar*, wxGetHomeDir(&home));
209     else
210         return _T("");
211 }
212
213 // returns %UserName%, $USER or just "user"
214 //
215 bool wxGetUserId(wxChar *buf, int n)
216 {
217     const wxChar *user = wxGetenv(_T("UserName"));
218
219     if (!user)
220         user = wxGetenv(_T("USER"));
221
222     if (!user)
223         user = _T("user");
224
225     wxStrncpy(buf, user, n);
226     return true;
227 }
228
229 bool wxGetUserName(wxChar *buf, int n)
230 {
231     return wxGetUserId(buf, n);
232 }
233
234 // returns %ComputerName%, or $HOSTNAME, or "host"
235 //
236 bool wxGetHostName(wxChar *buf, int n)
237 {
238     const wxChar *host = wxGetenv(_T("ComputerName"));
239
240     if (!host)
241         host = wxGetenv(_T("HOSTNAME"));
242
243     if (!host)
244         host = _T("host");
245
246     wxStrncpy(buf, host, n);
247     return true;
248 }
249
250 // adds %UserDnsDomain% to wxGetHostName()
251 //
252 bool wxGetFullHostName(wxChar *buf, int n)
253 {
254     wxGetHostName(buf, n);
255
256     const wxChar *domain = wxGetenv(_T("UserDnsDomain"));
257
258     if (domain)
259         wxStrncat(wxStrncat(buf, _T("."), n), domain, n);
260
261     return true;
262 }
263
264 //----------------------------------------------------------------------------
265 // Processes
266 //----------------------------------------------------------------------------
267
268 unsigned long wxGetProcessId()
269 {
270     return (unsigned long)getpid();
271 }
272
273 int wxKill(long pid, wxSignal sig, wxKillError *rc, int WXUNUSED(flags))
274 {
275     int result = -1;
276
277     if (pid != (long)wxGetProcessId())
278     {
279         result = raise(sig);
280         if (rc)
281             *rc = result == 0 ? wxKILL_OK : wxKILL_BAD_SIGNAL;
282     }
283     else
284     {
285         wxLogDebug(_T("wxKill can only send signals to the current process under MSDOS"));
286         if (rc)
287             *rc = wxKILL_NO_PROCESS;
288     }
289
290     return result;
291 }
292
293 bool wxShell(const wxString& command /*=wxEmptyString*/)
294 {
295     // FIXME: suspend/resume gui
296     int result = system(command);
297
298     if (result == -1)
299         wxLogSysError(_("can't execute '%s'"), command.c_str());
300
301     return result == 0;
302 }
303
304 long wxExecute(const wxString& command, int flags, wxProcess *process)
305 {
306     // FIXME: shouldn't depend on wxCmdLineParser
307     wxArrayString args(wxCmdLineParser::ConvertStringToArgs(command));
308     size_t n = args.size();
309     wxChar **argv = new wxChar*[n + 1];
310
311     argv[n] = NULL;
312     while (n-- > 0)
313         argv[n] = wx_const_cast(wxChar*, args[n].c_str());
314
315     long result = wxExecute(argv, flags, process);
316
317     delete [] argv;
318     return result;
319 }
320
321 #if wxUSE_STREAMS
322
323 // A wxFFileInputStream that deletes the file in it's destructor
324 //
325 class wxTempFileInStream : public wxFFileInputStream
326 {
327 public:
328     wxTempFileInStream(const wxString& name)
329         : wxFFileInputStream(name, _T("rt"))
330     { }
331
332     ~wxTempFileInStream()
333     {
334         m_file->Close();
335         wxRemoveFile(m_file->GetName());
336     }
337 };
338
339 // A file descriptor that can be redirected to a file
340 //
341 class wxRedirectableFd
342 {
343 public:
344     wxRedirectableFd(int fd) : m_fd(fd), m_dup(-1) { }
345     ~wxRedirectableFd();
346
347     // Redirect the descriptor to a file, similar to ANSI C's freopen, but
348     // for low level descriptors. The desctructor un-redirects. If O_CREAT
349     // is in the flags then the destructor will delete the file unless it is
350     // given away with Release().
351     bool Reopen(const wxString& name, int flags);
352
353     // un-redirect the redirected file descriptor, closing the file, and give
354     // away the filename without deleting it
355     wxString Release();
356
357 private:
358     // un-redirect the descriptor, closing the file
359     void Restore();
360
361     int m_fd;
362     int m_dup;
363     wxString m_name;
364 };
365
366 wxRedirectableFd::~wxRedirectableFd()
367 {
368     Restore();
369     if (!m_name.empty())
370         wxRemoveFile(m_name);
371 }
372
373 bool wxRedirectableFd::Reopen(const wxString& name, int flags)
374 {
375     wxASSERT(m_dup == -1);
376     bool result = false;
377
378     // save a duplicate so that the descriptor can be closed now and
379     // restored later
380     m_dup = dup(m_fd);
381
382     if (m_dup != -1)
383     {
384         int tmp = open(name.mb_str(), flags);
385
386         if (tmp != -1)
387         {
388             close(m_fd);
389
390             if (flags & O_CREAT)
391                 m_name = name;
392
393             result = dup2(tmp, m_fd) == m_fd;
394             close(tmp);
395         }
396     }
397
398     if (!result)
399         wxLogSysError(_("error opening '%s'"), name.c_str());
400
401     return result;
402 }
403
404 void wxRedirectableFd::Restore()
405 {
406     if (m_dup != -1)
407     {
408         close(m_fd);
409         dup2(m_dup, m_fd);
410         close(m_dup);
411         m_dup = -1;
412     }
413 }
414
415 wxString wxRedirectableFd::Release()
416 {
417     Restore();
418     wxString name = m_name;
419     m_name.clear();
420     return name;
421 }
422
423 #endif // wxUSE_STREAMS
424
425 // wxExecute implementation
426 //
427 long wxExecute(wxChar **argv, int flags, wxProcess *process)
428 {
429 #if wxUSE_STREAMS
430     const int STDIN = 0;
431     const int STDOUT = 1;
432     const int STDERR = 2;
433
434     wxRedirectableFd in(STDIN), out(STDOUT), err(STDERR);
435     bool redirect = process && process->IsRedirected() && (flags & wxEXEC_SYNC);
436
437     if (redirect)
438     {
439         // close stdin/out/err and reopen them as files
440         if (!in.Reopen(_T("NUL"), O_RDONLY | O_TEXT))
441             return -1;
442
443         if (!out.Reopen(wxFileName::CreateTempFileName(_T("out")),
444                         O_CREAT | O_WRONLY | O_TRUNC | O_TEXT))
445             return -1;
446
447         if (!err.Reopen(wxFileName::CreateTempFileName(_T("err")),
448                         O_CREAT | O_WRONLY | O_TRUNC | O_TEXT))
449             return -1;
450     }
451 #endif // wxUSE_STREAMS
452
453     // FIXME: suspend/resume gui
454     int mode = flags & wxEXEC_SYNC ? P_WAIT : P_NOWAIT;
455     int result = spawnvp(mode, argv[0], argv);
456
457     if (result == -1)
458         wxLogSysError(_("can't execute '%s'"), argv[0]);
459
460 #if wxUSE_STREAMS
461     if (redirect)
462         process->SetPipeStreams(new wxTempFileInStream(out.Release()),
463                                 new wxFFileOutputStream(_T("NUL"), _T("wt")),
464                                 new wxTempFileInStream(err.Release()));
465 #endif // wxUSE_STREAMS
466
467     return result;
468 }
469
470 //----------------------------------------------------------------------------
471 // Traits for console apps
472 //----------------------------------------------------------------------------
473
474 wxToolkitInfo& wxConsoleAppTraits::GetToolkitInfo()
475 {
476     static wxToolkitInfo info;
477     info.versionMajor = _osmajor;
478     info.versionMinor = _osminor;
479     info.name = _T("wxBase");
480     info.os = wxDOS;
481     return info;
482 }
483
484 //----------------------------------------------------------------------------
485 // OS Description
486 //----------------------------------------------------------------------------
487
488 wxString wxGetOsDescription()
489 {
490     wxString osname(_T("DOS"));
491     return osname;
492 }