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