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