1///////////////////////////////////////////////////////////////////////////// 2// Name: src/msdos/utils.cpp 3// Purpose: DOS implementations of utility functions 4// Author: Vaclav Slavik, M.J.Wetherell 5// Id: $Id: utilsdos.cpp 41020 2006-09-05 20:47:48Z VZ $ 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 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) 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 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 82//---------------------------------------------------------------------------- 83// Get/Set environment variables 84//---------------------------------------------------------------------------- 85 86bool 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 99bool 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// 125const 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 203wxChar *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// 215bool 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 229bool wxGetUserName(wxChar *buf, int n) 230{ 231 return wxGetUserId(buf, n); 232} 233 234// returns %ComputerName%, or $HOSTNAME, or "host" 235// 236bool 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// 252bool 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 268unsigned long wxGetProcessId() 269{ 270 return (unsigned long)getpid(); 271} 272 273int 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 293bool 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 304long 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// 325class wxTempFileInStream : public wxFFileInputStream 326{ 327public: 328 wxTempFileInStream(const wxString& name) 329 : wxFFileInputStream(name, _T("rt")) 330 { } 331 332 virtual ~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// 341class wxRedirectableFd 342{ 343public: 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 357private: 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 366wxRedirectableFd::~wxRedirectableFd() 367{ 368 Restore(); 369 if (!m_name.empty()) 370 wxRemoveFile(m_name); 371} 372 373bool 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 404void 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 415wxString 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// 427long 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//---------------------------------------------------------------------------- 472// OS-related 473//---------------------------------------------------------------------------- 474 475wxString wxGetOsDescription() 476{ 477 wxString osname(_T("DOS")); 478 return osname; 479} 480 481wxOperatingSystemId wxGetOsVersion(int *verMaj, int *verMin) 482{ 483 if ( verMaj ) 484 *verMaj = _osmajor; 485 if ( verMin ) 486 *verMin = _osminor; 487 488 return wxOS_DOS; 489} 490 491bool wxIsPlatform64Bit() 492{ 493 return false; 494} 495 496