s/wxSplitPath/wxFileName::SplitPath
[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 static bool wxDoSetEnv(const wxString& variable, const char *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 bool wxSetEnv(const wxString& variable, const wxString& value)
116 {
117 return wxDoSetEnv(variable, value.mb_str());
118 }
119
120 bool wxUnsetEnv(const wxString& variable)
121 {
122 return wxDoSetEnv(variable, NULL);
123 }
124
125
126 //----------------------------------------------------------------------------
127 // Hostname, username, home directory
128 //----------------------------------------------------------------------------
129
130 // Based on the MSW implementation
131 //
132 // Respects the following environment variables in this order: %HomeDrive% +
133 // %HomePath%, %UserProfile%, $HOME. Otherwise takes program's directory if
134 // wxApp has been initialised, otherwise returns ".".
135 //
136 const wxChar* wxGetHomeDir(wxString *home)
137 {
138 wxString& strDir = *home;
139
140 strDir.clear();
141
142 // try HOMEDRIVE/PATH
143 const wxChar *szHome = wxGetenv(wxT("HOMEDRIVE"));
144 if ( szHome != NULL )
145 strDir << szHome;
146 szHome = wxGetenv(wxT("HOMEPATH"));
147
148 if ( szHome != NULL )
149 {
150 strDir << szHome;
151
152 // the idea is that under NT these variables have default values of
153 // "%systemdrive%:" and "\\". As we don't want to create our config
154 // files in the root directory of the system drive, we will create it
155 // in our program's dir. However, if the user took care to set
156 // HOMEPATH to something other than "\\", we suppose that he knows
157 // what he is doing and use the supplied value.
158 if ( wxStrcmp(szHome, wxT("\\")) == 0 )
159 strDir.clear();
160 }
161
162 if ( strDir.empty() )
163 {
164 // If we have a valid USERPROFILE directory, as is the case in
165 // Windows NT, 2000 and XP, we should use that as our home directory.
166 szHome = wxGetenv(wxT("USERPROFILE"));
167
168 if ( szHome != NULL )
169 strDir = szHome;
170 }
171
172 if ( strDir.empty() )
173 {
174 // If we have a valid HOME directory, as is used on many machines
175 // that have unix utilities on them, we should use that.
176 szHome = wxGetenv(wxT("HOME"));
177
178 if ( szHome != NULL )
179 {
180 strDir = szHome;
181 // when msys sets %HOME% it uses '/' (cygwin uses '\\')
182 strDir.Replace(_T("/"), _T("\\"));
183 }
184 }
185
186 if ( !strDir.empty() )
187 {
188 // sometimes the value of HOME may be "%USERPROFILE%", so reexpand the
189 // value once again, it shouldn't hurt anyhow
190 strDir = wxExpandEnvVars(strDir);
191 }
192 else // fall back to the program directory
193 {
194 if ( wxTheApp )
195 {
196 wxString prog(wxTheApp->argv[0]);
197 #ifdef __DJGPP__
198 // djgpp startup code switches the slashes around, so restore them
199 prog.Replace(_T("/"), _T("\\"));
200 #endif
201 // it needs to be a full path to be usable
202 if ( prog.compare(1, 2, _T(":\\")) == 0 )
203 wxFileName::SplitPath(prog, &strDir, NULL, NULL);
204 }
205 if ( strDir.empty() )
206 {
207 strDir = _T(".");
208 }
209 }
210
211 return strDir.c_str();
212 }
213
214 wxString wxGetUserHome(const wxString& user)
215 {
216 wxString home;
217
218 if (user.empty() || user == wxGetUserId())
219 wxGetHomeDir(&home);
220
221 return home;
222 }
223
224 // returns %UserName%, $USER or just "user"
225 //
226 bool wxGetUserId(wxChar *buf, int n)
227 {
228 const wxChar *user = wxGetenv(_T("UserName"));
229
230 if (!user)
231 user = wxGetenv(_T("USER"));
232
233 if (!user)
234 user = _T("user");
235
236 wxStrlcpy(buf, user, n);
237 return true;
238 }
239
240 bool wxGetUserName(wxChar *buf, int n)
241 {
242 return wxGetUserId(buf, n);
243 }
244
245 // returns %ComputerName%, or $HOSTNAME, or "host"
246 //
247 bool wxGetHostName(wxChar *buf, int n)
248 {
249 const wxChar *host = wxGetenv(_T("ComputerName"));
250
251 if (!host)
252 host = wxGetenv(_T("HOSTNAME"));
253
254 if (!host)
255 host = _T("host");
256
257 wxStrlcpy(buf, host, n);
258 return true;
259 }
260
261 // adds %UserDnsDomain% to wxGetHostName()
262 //
263 bool wxGetFullHostName(wxChar *buf, int n)
264 {
265 wxGetHostName(buf, n);
266
267 const wxChar *domain = wxGetenv(_T("UserDnsDomain"));
268
269 if (domain)
270 wxStrncat(wxStrncat(buf, _T("."), n), domain, n);
271
272 return true;
273 }
274
275 //----------------------------------------------------------------------------
276 // Processes
277 //----------------------------------------------------------------------------
278
279 unsigned long wxGetProcessId()
280 {
281 return (unsigned long)getpid();
282 }
283
284 int wxKill(long pid, wxSignal sig, wxKillError *rc, int WXUNUSED(flags))
285 {
286 int result = -1;
287
288 if (pid != (long)wxGetProcessId())
289 {
290 result = raise(sig);
291 if (rc)
292 *rc = result == 0 ? wxKILL_OK : wxKILL_BAD_SIGNAL;
293 }
294 else
295 {
296 wxLogDebug(_T("wxKill can only send signals to the current process under MSDOS"));
297 if (rc)
298 *rc = wxKILL_NO_PROCESS;
299 }
300
301 return result;
302 }
303
304 bool wxShell(const wxString& command /*=wxEmptyString*/)
305 {
306 // FIXME: suspend/resume gui
307 int result = system(command);
308
309 if (result == -1)
310 wxLogSysError(_("can't execute '%s'"), command.c_str());
311
312 return result == 0;
313 }
314
315 long wxExecute(const wxString& command, int flags, wxProcess *process)
316 {
317 // FIXME: shouldn't depend on wxCmdLineParser
318 wxArrayString args(wxCmdLineParser::ConvertStringToArgs(command));
319 size_t n = args.size();
320 wxChar **argv = new wxChar*[n + 1];
321
322 argv[n] = NULL;
323 while (n-- > 0)
324 argv[n] = const_cast<wxChar*>((const char *)args[n].c_str());
325
326 long result = wxExecute(argv, flags, process);
327
328 delete [] argv;
329 return result;
330 }
331
332 #if wxUSE_STREAMS
333
334 // A wxFFileInputStream that deletes the file in it's destructor
335 //
336 class wxTempFileInStream : public wxFFileInputStream
337 {
338 public:
339 wxTempFileInStream(const wxString& name)
340 : wxFFileInputStream(name, _T("rt"))
341 { }
342
343 virtual ~wxTempFileInStream()
344 {
345 m_file->Close();
346 wxRemoveFile(m_file->GetName());
347 }
348 };
349
350 // A file descriptor that can be redirected to a file
351 //
352 class wxRedirectableFd
353 {
354 public:
355 wxRedirectableFd(int fd) : m_fd(fd), m_dup(-1) { }
356 ~wxRedirectableFd();
357
358 // Redirect the descriptor to a file, similar to ANSI C's freopen, but
359 // for low level descriptors. The desctructor un-redirects. If O_CREAT
360 // is in the flags then the destructor will delete the file unless it is
361 // given away with Release().
362 bool Reopen(const wxString& name, int flags);
363
364 // un-redirect the redirected file descriptor, closing the file, and give
365 // away the filename without deleting it
366 wxString Release();
367
368 private:
369 // un-redirect the descriptor, closing the file
370 void Restore();
371
372 int m_fd;
373 int m_dup;
374 wxString m_name;
375 };
376
377 wxRedirectableFd::~wxRedirectableFd()
378 {
379 Restore();
380 if (!m_name.empty())
381 wxRemoveFile(m_name);
382 }
383
384 bool wxRedirectableFd::Reopen(const wxString& name, int flags)
385 {
386 wxASSERT(m_dup == -1);
387 bool result = false;
388
389 // save a duplicate so that the descriptor can be closed now and
390 // restored later
391 m_dup = dup(m_fd);
392
393 if (m_dup != -1)
394 {
395 int tmp = open(name.mb_str(), flags);
396
397 if (tmp != -1)
398 {
399 close(m_fd);
400
401 if (flags & O_CREAT)
402 m_name = name;
403
404 result = dup2(tmp, m_fd) == m_fd;
405 close(tmp);
406 }
407 }
408
409 if (!result)
410 wxLogSysError(_("error opening '%s'"), name.c_str());
411
412 return result;
413 }
414
415 void wxRedirectableFd::Restore()
416 {
417 if (m_dup != -1)
418 {
419 close(m_fd);
420 dup2(m_dup, m_fd);
421 close(m_dup);
422 m_dup = -1;
423 }
424 }
425
426 wxString wxRedirectableFd::Release()
427 {
428 Restore();
429 wxString name = m_name;
430 m_name.clear();
431 return name;
432 }
433
434 #endif // wxUSE_STREAMS
435
436 // wxExecute implementation
437 //
438 long wxExecute(wxChar **argv, int flags, wxProcess *process)
439 {
440 #if wxUSE_STREAMS
441 const int STDIN = 0;
442 const int STDOUT = 1;
443 const int STDERR = 2;
444
445 wxRedirectableFd in(STDIN), out(STDOUT), err(STDERR);
446 bool redirect = process && process->IsRedirected() && (flags & wxEXEC_SYNC);
447
448 if (redirect)
449 {
450 // close stdin/out/err and reopen them as files
451 if (!in.Reopen(_T("NUL"), O_RDONLY | O_TEXT))
452 return -1;
453
454 if (!out.Reopen(wxFileName::CreateTempFileName(_T("out")),
455 O_CREAT | O_WRONLY | O_TRUNC | O_TEXT))
456 return -1;
457
458 if (!err.Reopen(wxFileName::CreateTempFileName(_T("err")),
459 O_CREAT | O_WRONLY | O_TRUNC | O_TEXT))
460 return -1;
461 }
462 #endif // wxUSE_STREAMS
463
464 // FIXME: suspend/resume gui
465 int mode = flags & wxEXEC_SYNC ? P_WAIT : P_NOWAIT;
466 int result = spawnvp(mode, argv[0], argv);
467
468 if (result == -1)
469 wxLogSysError(_("can't execute '%s'"), argv[0]);
470
471 #if wxUSE_STREAMS
472 if (redirect)
473 process->SetPipeStreams(new wxTempFileInStream(out.Release()),
474 new wxFFileOutputStream(_T("NUL"), _T("wt")),
475 new wxTempFileInStream(err.Release()));
476 #endif // wxUSE_STREAMS
477
478 return result;
479 }
480
481
482 //----------------------------------------------------------------------------
483 // OS-related
484 //----------------------------------------------------------------------------
485
486 wxString wxGetOsDescription()
487 {
488 wxString osname(_T("DOS"));
489 return osname;
490 }
491
492 wxOperatingSystemId wxGetOsVersion(int *verMaj, int *verMin)
493 {
494 if ( verMaj )
495 *verMaj = _osmajor;
496 if ( verMin )
497 *verMin = _osminor;
498
499 return wxOS_DOS;
500 }
501
502 bool wxIsPlatform64Bit()
503 {
504 return false;
505 }
506