]> git.saurik.com Git - wxWidgets.git/blame - src/msdos/utilsdos.cpp
Fix command line parsing in media player sample.
[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
MW
5// Id: $Id$
6// Copyright: (c) 2001-2002 SciTech Software, Inc. (www.scitechsoft.com)
a3c0d768 7// (c) 2005 M.J.Wetherell
81d9e625
MW
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"
df91131c
WS
19
20#ifndef WX_PRECOMP
21 #include "wx/string.h"
88a7a4e1 22 #include "wx/intl.h"
e4db172a 23 #include "wx/log.h"
670f9935 24 #include "wx/app.h"
df91131c 25#endif
81d9e625 26
81d9e625 27#include "wx/apptrait.h"
81d9e625 28#include "wx/process.h"
a3c0d768 29#include "wx/confbase.h" // for wxExpandEnvVars()
a3c0d768
MW
30#include "wx/cmdline.h"
31#include "wx/filename.h"
32#include "wx/wfstream.h"
81d9e625
MW
33
34#include <stdarg.h>
35#include <string.h>
36#include <sys/stat.h>
37#include <sys/types.h>
38#include <unistd.h>
a3c0d768 39#include <signal.h>
81d9e625 40#include <time.h>
a3c0d768
MW
41#include <dos.h>
42#include <process.h>
81d9e625
MW
43
44//----------------------------------------------------------------------------
a3c0d768 45// Sleep
81d9e625
MW
46//----------------------------------------------------------------------------
47
48void wxSleep(int nSecs)
49{
50 wxMilliSleep(1000 * nSecs);
51}
52
53void 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)
a3c0d768
MW
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 }
81d9e625
MW
70#endif
71}
72
73void wxMicroSleep(unsigned long microseconds)
74{
75#if HAVE_USLEEP || defined __DJGPP__
76 usleep(microseconds);
77#else
78 wxMilliSleep(microseconds/1000);
79#endif
80}
81
a3c0d768
MW
82//----------------------------------------------------------------------------
83// Get/Set environment variables
84//----------------------------------------------------------------------------
81d9e625
MW
85
86bool wxGetEnv(const wxString& var, wxString *value)
87{
88 // wxGetenv is defined as getenv()
89 wxChar *p = wxGetenv(var);
90 if ( !p )
df91131c 91 return false;
81d9e625
MW
92
93 if ( value )
94 *value = p;
95
df91131c 96 return true;
81d9e625
MW
97}
98
90a77e64 99static bool wxDoSetEnv(const wxString& variable, const char *value)
81d9e625
MW
100{
101 wxString s = variable;
102 if ( value )
9a83f860 103 s << wxT('=') << value;
81d9e625
MW
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
90a77e64
VS
115bool wxSetEnv(const wxString& variable, const wxString& value)
116{
117 return wxDoSetEnv(variable, value.mb_str());
118}
119
120bool wxUnsetEnv(const wxString& variable)
121{
122 return wxDoSetEnv(variable, NULL);
123}
124
125
a3c0d768
MW
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//
81d9e625
MW
136const wxChar* wxGetHomeDir(wxString *home)
137{
a3c0d768 138 wxString& strDir = *home;
81d9e625 139
a3c0d768
MW
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 '\\')
9a83f860 182 strDir.Replace(wxT("/"), wxT("\\"));
a3c0d768
MW
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
9a83f860 199 prog.Replace(wxT("/"), wxT("\\"));
a3c0d768
MW
200#endif
201 // it needs to be a full path to be usable
9a83f860 202 if ( prog.compare(1, 2, wxT(":\\")) == 0 )
bd365871 203 wxFileName::SplitPath(prog, &strDir, NULL, NULL);
a3c0d768
MW
204 }
205 if ( strDir.empty() )
206 {
9a83f860 207 strDir = wxT(".");
a3c0d768
MW
208 }
209 }
210
211 return strDir.c_str();
81d9e625
MW
212}
213
14d63513 214wxString wxGetUserHome(const wxString& user)
81d9e625 215{
14d63513 216 wxString home;
a3c0d768
MW
217
218 if (user.empty() || user == wxGetUserId())
14d63513
VZ
219 wxGetHomeDir(&home);
220
221 return home;
81d9e625
MW
222}
223
a3c0d768
MW
224// returns %UserName%, $USER or just "user"
225//
226bool wxGetUserId(wxChar *buf, int n)
81d9e625 227{
9a83f860 228 const wxChar *user = wxGetenv(wxT("UserName"));
a3c0d768
MW
229
230 if (!user)
9a83f860 231 user = wxGetenv(wxT("USER"));
a3c0d768
MW
232
233 if (!user)
9a83f860 234 user = wxT("user");
a3c0d768 235
e408bf52 236 wxStrlcpy(buf, user, n);
a3c0d768 237 return true;
81d9e625
MW
238}
239
a3c0d768 240bool wxGetUserName(wxChar *buf, int n)
81d9e625 241{
a3c0d768 242 return wxGetUserId(buf, n);
81d9e625
MW
243}
244
a3c0d768
MW
245// returns %ComputerName%, or $HOSTNAME, or "host"
246//
247bool wxGetHostName(wxChar *buf, int n)
81d9e625 248{
9a83f860 249 const wxChar *host = wxGetenv(wxT("ComputerName"));
df91131c 250
a3c0d768 251 if (!host)
9a83f860 252 host = wxGetenv(wxT("HOSTNAME"));
a3c0d768
MW
253
254 if (!host)
9a83f860 255 host = wxT("host");
a3c0d768 256
e408bf52 257 wxStrlcpy(buf, host, n);
a3c0d768 258 return true;
81d9e625
MW
259}
260
a3c0d768
MW
261// adds %UserDnsDomain% to wxGetHostName()
262//
263bool wxGetFullHostName(wxChar *buf, int n)
264{
265 wxGetHostName(buf, n);
266
9a83f860 267 const wxChar *domain = wxGetenv(wxT("UserDnsDomain"));
a3c0d768
MW
268
269 if (domain)
9a83f860 270 wxStrncat(wxStrncat(buf, wxT("."), n), domain, n);
a3c0d768
MW
271
272 return true;
273}
274
275//----------------------------------------------------------------------------
276// Processes
277//----------------------------------------------------------------------------
278
279unsigned long wxGetProcessId()
81d9e625 280{
a3c0d768 281 return (unsigned long)getpid();
81d9e625
MW
282}
283
a3c0d768 284int wxKill(long pid, wxSignal sig, wxKillError *rc, int WXUNUSED(flags))
81d9e625 285{
a3c0d768
MW
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 {
9a83f860 296 wxLogDebug(wxT("wxKill can only send signals to the current process under MSDOS"));
a3c0d768
MW
297 if (rc)
298 *rc = wxKILL_NO_PROCESS;
299 }
300
301 return result;
81d9e625
MW
302}
303
a3c0d768 304bool wxShell(const wxString& command /*=wxEmptyString*/)
81d9e625 305{
a3c0d768
MW
306 // FIXME: suspend/resume gui
307 int result = system(command);
308
309 if (result == -1)
43b2d5e7 310 {
a3c0d768 311 wxLogSysError(_("can't execute '%s'"), command.c_str());
43b2d5e7 312 }
a3c0d768
MW
313
314 return result == 0;
81d9e625
MW
315}
316
164db92c
VZ
317long wxExecute(const wxString& command, int flags, wxProcess *process,
318 const wxExecuteEnv *env)
81d9e625 319{
a3c0d768
MW
320 // FIXME: shouldn't depend on wxCmdLineParser
321 wxArrayString args(wxCmdLineParser::ConvertStringToArgs(command));
322 size_t n = args.size();
323 wxChar **argv = new wxChar*[n + 1];
324
325 argv[n] = NULL;
326 while (n-- > 0)
5c33522f 327 argv[n] = const_cast<wxChar*>((const char *)args[n].c_str());
a3c0d768
MW
328
329 long result = wxExecute(argv, flags, process);
330
331 delete [] argv;
332 return result;
81d9e625
MW
333}
334
a3c0d768
MW
335#if wxUSE_STREAMS
336
337// A wxFFileInputStream that deletes the file in it's destructor
df91131c 338//
a3c0d768
MW
339class wxTempFileInStream : public wxFFileInputStream
340{
341public:
342 wxTempFileInStream(const wxString& name)
9a83f860 343 : wxFFileInputStream(name, wxT("rt"))
a3c0d768
MW
344 { }
345
d3c7fc99 346 virtual ~wxTempFileInStream()
a3c0d768
MW
347 {
348 m_file->Close();
349 wxRemoveFile(m_file->GetName());
350 }
351};
352
353// A file descriptor that can be redirected to a file
354//
355class wxRedirectableFd
356{
357public:
358 wxRedirectableFd(int fd) : m_fd(fd), m_dup(-1) { }
359 ~wxRedirectableFd();
360
361 // Redirect the descriptor to a file, similar to ANSI C's freopen, but
362 // for low level descriptors. The desctructor un-redirects. If O_CREAT
363 // is in the flags then the destructor will delete the file unless it is
364 // given away with Release().
365 bool Reopen(const wxString& name, int flags);
366
367 // un-redirect the redirected file descriptor, closing the file, and give
368 // away the filename without deleting it
369 wxString Release();
370
371private:
372 // un-redirect the descriptor, closing the file
373 void Restore();
374
375 int m_fd;
376 int m_dup;
377 wxString m_name;
378};
379
380wxRedirectableFd::~wxRedirectableFd()
381{
382 Restore();
383 if (!m_name.empty())
384 wxRemoveFile(m_name);
385}
386
387bool wxRedirectableFd::Reopen(const wxString& name, int flags)
388{
389 wxASSERT(m_dup == -1);
390 bool result = false;
391
392 // save a duplicate so that the descriptor can be closed now and
393 // restored later
394 m_dup = dup(m_fd);
395
396 if (m_dup != -1)
397 {
398 int tmp = open(name.mb_str(), flags);
399
400 if (tmp != -1)
401 {
402 close(m_fd);
403
404 if (flags & O_CREAT)
405 m_name = name;
406
407 result = dup2(tmp, m_fd) == m_fd;
408 close(tmp);
409 }
410 }
411
412 if (!result)
43b2d5e7 413 {
a3c0d768 414 wxLogSysError(_("error opening '%s'"), name.c_str());
43b2d5e7 415 }
a3c0d768
MW
416
417 return result;
418}
419
420void wxRedirectableFd::Restore()
421{
422 if (m_dup != -1)
423 {
424 close(m_fd);
425 dup2(m_dup, m_fd);
426 close(m_dup);
427 m_dup = -1;
428 }
429}
430
431wxString wxRedirectableFd::Release()
432{
433 Restore();
434 wxString name = m_name;
435 m_name.clear();
436 return name;
437}
438
439#endif // wxUSE_STREAMS
440
441// wxExecute implementation
442//
164db92c
VZ
443long wxExecute(wxChar **argv, int flags, wxProcess *process,
444 const wxString* cwd, const wxEnvVariableHashMap* env)
a3c0d768
MW
445{
446#if wxUSE_STREAMS
447 const int STDIN = 0;
448 const int STDOUT = 1;
449 const int STDERR = 2;
450
451 wxRedirectableFd in(STDIN), out(STDOUT), err(STDERR);
452 bool redirect = process && process->IsRedirected() && (flags & wxEXEC_SYNC);
453
454 if (redirect)
455 {
456 // close stdin/out/err and reopen them as files
9a83f860 457 if (!in.Reopen(wxT("NUL"), O_RDONLY | O_TEXT))
a3c0d768
MW
458 return -1;
459
9a83f860 460 if (!out.Reopen(wxFileName::CreateTempFileName(wxT("out")),
a3c0d768
MW
461 O_CREAT | O_WRONLY | O_TRUNC | O_TEXT))
462 return -1;
463
9a83f860 464 if (!err.Reopen(wxFileName::CreateTempFileName(wxT("err")),
a3c0d768
MW
465 O_CREAT | O_WRONLY | O_TRUNC | O_TEXT))
466 return -1;
467 }
468#endif // wxUSE_STREAMS
469
470 // FIXME: suspend/resume gui
471 int mode = flags & wxEXEC_SYNC ? P_WAIT : P_NOWAIT;
472 int result = spawnvp(mode, argv[0], argv);
473
474 if (result == -1)
43b2d5e7 475 {
a3c0d768 476 wxLogSysError(_("can't execute '%s'"), argv[0]);
43b2d5e7 477 }
a3c0d768
MW
478
479#if wxUSE_STREAMS
480 if (redirect)
481 process->SetPipeStreams(new wxTempFileInStream(out.Release()),
9a83f860 482 new wxFFileOutputStream(wxT("NUL"), wxT("wt")),
a3c0d768
MW
483 new wxTempFileInStream(err.Release()));
484#endif // wxUSE_STREAMS
485
486 return result;
487}
488
b5d09a5f
MW
489
490//----------------------------------------------------------------------------
8bb6b2c0 491// OS-related
b5d09a5f
MW
492//----------------------------------------------------------------------------
493
494wxString wxGetOsDescription()
495{
9a83f860 496 wxString osname(wxT("DOS"));
b5d09a5f
MW
497 return osname;
498}
8bb6b2c0
VZ
499
500wxOperatingSystemId wxGetOsVersion(int *verMaj, int *verMin)
501{
502 if ( verMaj )
503 *verMaj = _osmajor;
504 if ( verMin )
505 *verMin = _osminor;
506
507 return wxOS_DOS;
508}
509
73dd8b2d
MW
510bool wxIsPlatform64Bit()
511{
512 return false;
513}
514