SystemTools.cxx 127 KB
Newer Older
1 2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
3
#ifdef __osf__
4 5 6
#  define _OSF_SOURCE
#  define _POSIX_C_SOURCE 199506L
#  define _XOPEN_SOURCE_EXTENDED
7 8
#endif

9 10 11 12
#if defined(_WIN32) &&                                                        \
  (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) ||      \
   defined(__MINGW32__))
#  define KWSYS_WINDOWS_DIRS
13
#else
14 15 16
#  if defined(__SUNPRO_CC)
#    include <fcntl.h>
#  endif
17 18
#endif

19
#include "kwsysPrivate.h"
20
#include KWSYS_HEADER(RegularExpression.hxx)
21
#include KWSYS_HEADER(SystemTools.hxx)
22
#include KWSYS_HEADER(Directory.hxx)
23
#include KWSYS_HEADER(FStream.hxx)
24
#include KWSYS_HEADER(Encoding.h)
25
#include KWSYS_HEADER(Encoding.hxx)
26

27
#include <fstream>
28
#include <iostream>
29
#include <set>
30
#include <sstream>
31
#include <vector>
32

33 34 35
// Work-around CMake dependency scanning limitation.  This must
// duplicate the above list of headers.
#if 0
36 37 38 39 40
#  include "Directory.hxx.in"
#  include "Encoding.hxx.in"
#  include "FStream.hxx.in"
#  include "RegularExpression.hxx.in"
#  include "SystemTools.hxx.in"
41 42
#endif

43
#ifdef _MSC_VER
44
#  pragma warning(disable : 4786)
45 46
#endif

47
#if defined(__sgi) && !defined(__GNUC__)
48
#  pragma set woff 1375 /* base class destructor not virtual */
49
#endif
50

51 52
#include <ctype.h>
#include <errno.h>
53
#ifdef __QNX__
54
#  include <malloc.h> /* for malloc/free on QNX */
55
#endif
56 57 58
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
59 60
#include <time.h>

61
#if defined(_WIN32) && !defined(_MSC_VER) && defined(__GNUC__)
62
#  include <strings.h> /* for strcasecmp */
63 64
#endif

65
#ifdef _MSC_VER
66
#  define umask _umask // Note this is still umask on Borland
67 68
#endif

69 70
// support for realpath call
#ifndef _WIN32
71 72 73 74 75 76 77 78 79 80 81 82
#  include <limits.h>
#  include <pwd.h>
#  include <sys/ioctl.h>
#  include <sys/time.h>
#  include <sys/wait.h>
#  include <unistd.h>
#  include <utime.h>
#  ifndef __VMS
#    include <sys/param.h>
#    include <termios.h>
#  endif
#  include <signal.h> /* sigprocmask */
83 84
#endif

85 86
// Windows API.
#if defined(_WIN32)
87 88 89 90 91 92 93 94
#  include <windows.h>
#  include <winioctl.h>
#  ifndef INVALID_FILE_ATTRIBUTES
#    define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#  endif
#  if defined(_MSC_VER) && _MSC_VER >= 1800
#    define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
#  endif
95
#elif defined(__CYGWIN__)
96 97
#  include <windows.h>
#  undef _WIN32
98 99
#endif

100
#if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
101
extern char** environ;
102 103
#endif

104
#ifdef __CYGWIN__
105
#  include <sys/cygwin.h>
106 107
#endif

108
// getpwnam doesn't exist on Windows and Cray Xt3/Catamount
109
// same for TIOCGWINSZ
110 111
#if defined(_WIN32) || defined(__LIBCATAMOUNT__) ||                           \
  (defined(HAVE_GETPWNAM) && HAVE_GETPWNAM == 0)
112 113
#  undef HAVE_GETPWNAM
#  undef HAVE_TTY_INFO
114
#else
115 116
#  define HAVE_GETPWNAM 1
#  define HAVE_TTY_INFO 1
117 118
#endif

119
#define VTK_URL_PROTOCOL_REGEX "([a-zA-Z0-9]*)://(.*)"
120 121 122
#define VTK_URL_REGEX                                                         \
  "([a-zA-Z0-9]*)://(([A-Za-z0-9]+)(:([^:@]+))?@)?([^:@/]+)(:([0-9]+))?/"     \
  "(.+)?"
123

124
#ifdef _MSC_VER
125
#  include <sys/utime.h>
126
#else
127
#  include <utime.h>
128
#endif
129

130 131 132
// This is a hack to prevent warnings about these functions being
// declared but not referenced.
#if defined(__sgi) && !defined(__GNUC__)
133
#  include <sys/termios.h>
134
namespace KWSYS_NAMESPACE {
135 136 137 138 139 140 141 142 143
class SystemToolsHack
{
public:
  enum
  {
    Ref1 = sizeof(cfgetospeed(0)),
    Ref2 = sizeof(cfgetispeed(0)),
    Ref3 = sizeof(tcgetattr(0, 0)),
    Ref4 = sizeof(tcsetattr(0, 0, 0)),
144 145
    Ref5 = sizeof(cfsetospeed(0, 0)),
    Ref6 = sizeof(cfsetispeed(0, 0))
146 147 148 149
  };
};
}
#endif
150

151 152 153 154 155 156
#if defined(_WIN32) &&                                                        \
  (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) ||      \
   defined(__MINGW32__))
#  include <direct.h>
#  include <io.h>
#  define _unlink unlink
157
#endif
158 159 160

/* The maximum length of a file name.  */
#if defined(PATH_MAX)
161
#  define KWSYS_SYSTEMTOOLS_MAXPATH PATH_MAX
162
#elif defined(MAXPATHLEN)
163
#  define KWSYS_SYSTEMTOOLS_MAXPATH MAXPATHLEN
164
#else
165
#  define KWSYS_SYSTEMTOOLS_MAXPATH 16384
166
#endif
167
#if defined(__WATCOMC__)
168 169 170 171 172
#  include <direct.h>
#  define _mkdir mkdir
#  define _rmdir rmdir
#  define _getcwd getcwd
#  define _chdir chdir
173
#endif
174

175
#if defined(__BEOS__) && !defined(__ZETA__)
176 177
#  include <be/kernel/OS.h>
#  include <be/storage/Path.h>
178 179 180 181 182 183 184 185

// BeOS 5 doesn't have usleep(), but it has snooze(), which is identical.
static inline void usleep(unsigned int msec)
{
  ::snooze(msec);
}

// BeOS 5 also doesn't have realpath(), but its C++ API offers something close.
186
static inline char* realpath(const char* path, char* resolved_path)
187 188 189 190
{
  const size_t maxlen = KWSYS_SYSTEMTOOLS_MAXPATH;
  snprintf(resolved_path, maxlen, "%s", path);
  BPath normalized(resolved_path, NULL, true);
191 192 193 194
  const char* resolved = normalized.Path();
  if (resolved != NULL) // NULL == No such file.
  {
    if (snprintf(resolved_path, maxlen, "%s", resolved) < maxlen) {
195 196
      return resolved_path;
    }
197 198
  }
  return NULL; // something went wrong.
199 200 201
}
#endif

202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
#ifdef _WIN32
static time_t windows_filetime_to_posix_time(const FILETIME& ft)
{
  LARGE_INTEGER date;
  date.HighPart = ft.dwHighDateTime;
  date.LowPart = ft.dwLowDateTime;

  // removes the diff between 1970 and 1601
  date.QuadPart -= ((LONGLONG)(369 * 365 + 89) * 24 * 3600 * 10000000);

  // converts back from 100-nanoseconds to seconds
  return date.QuadPart / 10000000;
}
#endif

217
#ifdef KWSYS_WINDOWS_DIRS
218
#  include <wctype.h>
219

220
inline int Mkdir(const std::string& dir)
221
{
222
  return _wmkdir(
223
    KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str());
224
}
225
inline int Rmdir(const std::string& dir)
226
{
227
  return _wrmdir(
228
    KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str());
229
}
230 231
inline const char* Getcwd(char* buf, unsigned int len)
{
232
  std::vector<wchar_t> w_buf(len);
233
  if (_wgetcwd(&w_buf[0], len)) {
234 235 236 237 238 239 240 241 242 243
    size_t nlen = kwsysEncoding_wcstombs(buf, &w_buf[0], len);
    if (nlen == static_cast<size_t>(-1)) {
      return 0;
    }
    if (nlen < len) {
      // make sure the drive letter is capital
      if (nlen > 1 && buf[1] == ':') {
        buf[0] = toupper(buf[0]);
      }
      return buf;
244 245
    }
  }
246
  return 0;
247
}
248
inline int Chdir(const std::string& dir)
249
{
250
#  if defined(__BORLANDC__)
251
  return chdir(dir.c_str());
252
#  else
253
  return _wchdir(KWSYS_NAMESPACE::Encoding::ToWide(dir).c_str());
254
#  endif
255
}
256
inline void Realpath(const std::string& path, std::string& resolved_path,
257
                     std::string* errorMessage = 0)
258
{
259
  std::wstring tmp = KWSYS_NAMESPACE::Encoding::ToWide(path);
260
  wchar_t* ptemp;
261
  wchar_t fullpath[MAX_PATH];
262 263 264
  DWORD bufferLen = GetFullPathNameW(
    tmp.c_str(), sizeof(fullpath) / sizeof(fullpath[0]), fullpath, &ptemp);
  if (bufferLen < sizeof(fullpath) / sizeof(fullpath[0])) {
265
    resolved_path = KWSYS_NAMESPACE::Encoding::ToNarrow(fullpath);
266
    KWSYS_NAMESPACE::SystemTools::ConvertToUnixSlashes(resolved_path);
267 268
  } else if (errorMessage) {
    if (bufferLen) {
269
      *errorMessage = "Destination path buffer size too small.";
270
    } else if (unsigned int errorId = GetLastError()) {
271
      LPSTR message = NULL;
272 273 274 275 276
      DWORD size = FormatMessageA(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
          FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL, errorId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPSTR)&message, 0, NULL);
277 278
      *errorMessage = std::string(message, size);
      LocalFree(message);
279
    } else {
280
      *errorMessage = "Unknown error.";
281
    }
282 283

    resolved_path = "";
284
  } else {
285
    resolved_path = path;
286
  }
287
}
288
#else
289
#  include <sys/types.h>
290

291 292
#  include <fcntl.h>
#  include <unistd.h>
293
inline int Mkdir(const std::string& dir)
294
{
295
  return mkdir(dir.c_str(), 00777);
296
}
297
inline int Rmdir(const std::string& dir)
298
{
299
  return rmdir(dir.c_str());
300
}
301 302
inline const char* Getcwd(char* buf, unsigned int len)
{
303
  return getcwd(buf, len);
304
}
305

306
inline int Chdir(const std::string& dir)
307
{
308
  return chdir(dir.c_str());
309
}
310
inline void Realpath(const std::string& path, std::string& resolved_path,
311
                     std::string* errorMessage = KWSYS_NULLPTR)
312
{
313
  char resolved_name[KWSYS_SYSTEMTOOLS_MAXPATH];
314

315
  errno = 0;
316 317
  char* ret = realpath(path.c_str(), resolved_name);
  if (ret) {
318
    resolved_path = ret;
319 320
  } else if (errorMessage) {
    if (errno) {
321
      *errorMessage = strerror(errno);
322
    } else {
323
      *errorMessage = "Unknown error.";
324
    }
325 326

    resolved_path = "";
327
  } else {
328 329
    // if path resolution fails, return what was passed in
    resolved_path = path;
330
  }
331
}
332 333
#endif

334 335
#if !defined(_WIN32) && defined(__COMO__)
// Hack for como strict mode to avoid defining _SVID_SOURCE or _BSD_SOURCE.
336 337 338 339 340 341 342
extern "C" {
extern FILE* popen(__const char* __command, __const char* __modes) __THROW;
extern int pclose(FILE* __stream) __THROW;
extern char* realpath(__const char* __restrict __name,
                      char* __restrict __resolved) __THROW;
extern char* strdup(__const char* __s) __THROW;
extern int putenv(char* __string) __THROW;
343 344
}
#endif
345

346
namespace KWSYS_NAMESPACE {
347

348 349 350 351 352
double SystemTools::GetTime(void)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
  FILETIME ft;
  GetSystemTimeAsFileTime(&ft);
353 354
  return (429.4967296 * ft.dwHighDateTime + 0.0000001 * ft.dwLowDateTime -
          11644473600.0);
355 356
#else
  struct timeval t;
357
  gettimeofday(&t, KWSYS_NULLPTR);
358
  return 1.0 * double(t.tv_sec) + 0.000001 * double(t.tv_usec);
359 360 361
#endif
}

362
class SystemToolsTranslationMap : public std::map<std::string, std::string>
363 364 365
{
};

366
/* Type of character storing the environment.  */
367 368 369
#if defined(_WIN32)
typedef wchar_t envchar;
#else
370
typedef char envchar;
371
#endif
372

373 374 375
/* Order by environment key only (VAR from VAR=VALUE).  */
struct kwsysEnvCompare
{
376 377
  bool operator()(const envchar* l, const envchar* r) const
  {
378 379 380
#if defined(_WIN32)
    const wchar_t* leq = wcschr(l, L'=');
    const wchar_t* req = wcschr(r, L'=');
381 382 383 384 385 386 387
    size_t llen = leq ? (leq - l) : wcslen(l);
    size_t rlen = req ? (req - r) : wcslen(r);
    if (llen == rlen) {
      return wcsncmp(l, r, llen) < 0;
    } else {
      return wcscmp(l, r) < 0;
    }
388
#else
389 390
    const char* leq = strchr(l, '=');
    const char* req = strchr(r, '=');
391 392 393 394 395 396
    size_t llen = leq ? (leq - l) : strlen(l);
    size_t rlen = req ? (req - r) : strlen(r);
    if (llen == rlen) {
      return strncmp(l, r, llen) < 0;
    } else {
      return strcmp(l, r) < 0;
397
    }
398 399
#endif
  }
400 401
};

402
class kwsysEnvSet : public std::set<const envchar*, kwsysEnvCompare>
403 404 405 406
{
public:
  class Free
  {
407
    const envchar* Env;
408

409
  public:
410 411 412 413
    Free(const envchar* env)
      : Env(env)
    {
    }
414
    ~Free() { free(const_cast<envchar*>(this->Env)); }
415 416
  };

417
  const envchar* Release(const envchar* env)
418
  {
419
    const envchar* old = KWSYS_NULLPTR;
420
    iterator i = this->find(env);
421
    if (i != this->end()) {
422 423 424
      old = *i;
      this->erase(i);
    }
425 426
    return old;
  }
427 428
};

429 430 431
#ifdef _WIN32
struct SystemToolsPathCaseCmp
{
432
  bool operator()(std::string const& l, std::string const& r) const
433
  {
434
#  ifdef _MSC_VER
435
    return _stricmp(l.c_str(), r.c_str()) < 0;
436
#  elif defined(__GNUC__)
437
    return strcasecmp(l.c_str(), r.c_str()) < 0;
438
#  else
439
    return SystemTools::Strucmp(l.c_str(), r.c_str()) < 0;
440
#  endif
441
  }
442 443
};

444 445 446 447
class SystemToolsPathCaseMap
  : public std::map<std::string, std::string, SystemToolsPathCaseCmp>
{
};
448

449 450 451
class SystemToolsEnvMap : public std::map<std::string, std::string>
{
};
452 453
#endif

454
// adds the elements of the env variable path to the arg passed in
455
void SystemTools::GetPath(std::vector<std::string>& path, const char* env)
456
{
457
  size_t const old_size = path.size();
458
#if defined(_WIN32) && !defined(__CYGWIN__)
459
  const char pathSep = ';';
460
#else
461
  const char pathSep = ':';
462
#endif
463
  if (!env) {
464
    env = "PATH";
465
  }
466
  std::string pathEnv;
467
  if (!SystemTools::GetEnv(env, pathEnv)) {
468
    return;
469
  }
470

471
  // A hack to make the below algorithm work.
472
  if (!pathEnv.empty() && *pathEnv.rbegin() != pathSep) {
473
    pathEnv += pathSep;
474 475
  }
  std::string::size_type start = 0;
476
  bool done = false;
477
  while (!done) {
478
    std::string::size_type endpos = pathEnv.find(pathSep, start);
479 480 481 482
    if (endpos != std::string::npos) {
      path.push_back(pathEnv.substr(start, endpos - start));
      start = endpos + 1;
    } else {
483 484
      done = true;
    }
485 486 487
  }
  for (std::vector<std::string>::iterator i = path.begin() + old_size;
       i != path.end(); ++i) {
488
    SystemTools::ConvertToUnixSlashes(*i);
489
  }
490 491
}

492
const char* SystemTools::GetEnvImpl(const char* key)
Brad King's avatar
Brad King committed
493
{
494
  const char* v = KWSYS_NULLPTR;
495 496
#if defined(_WIN32)
  std::string env;
497
  if (SystemTools::GetEnv(key, env)) {
498 499 500
    std::string& menv = (*SystemTools::EnvMap)[key];
    menv = env;
    v = menv.c_str();
501
  }
502
#else
503
  v = getenv(key);
504
#endif
505
  return v;
Brad King's avatar
Brad King committed
506 507
}

508 509 510 511 512
const char* SystemTools::GetEnv(const char* key)
{
  return SystemTools::GetEnvImpl(key);
}

513
const char* SystemTools::GetEnv(const std::string& key)
514
{
515
  return SystemTools::GetEnvImpl(key.c_str());
516 517
}

518
bool SystemTools::GetEnv(const char* key, std::string& result)
Brad King's avatar
Brad King committed
519
{
520 521 522
#if defined(_WIN32)
  const std::wstring wkey = Encoding::ToWide(key);
  const wchar_t* wv = _wgetenv(wkey.c_str());
523
  if (wv) {
524 525
    result = Encoding::ToNarrow(wv);
    return true;
526
  }
527
#else
Brad King's avatar
Brad King committed
528
  const char* v = getenv(key);
529
  if (v) {
Brad King's avatar
Brad King committed
530 531
    result = v;
    return true;
532
  }
533
#endif
534
  return false;
Brad King's avatar
Brad King committed
535
}
536

537
bool SystemTools::GetEnv(const std::string& key, std::string& result)
538 539 540 541
{
  return SystemTools::GetEnv(key.c_str(), result);
}

542 543 544 545 546 547 548 549
bool SystemTools::HasEnv(const char* key)
{
#if defined(_WIN32)
  const std::wstring wkey = Encoding::ToWide(key);
  const wchar_t* v = _wgetenv(wkey.c_str());
#else
  const char* v = getenv(key);
#endif
550
  return v != KWSYS_NULLPTR;
551 552 553 554 555 556 557
}

bool SystemTools::HasEnv(const std::string& key)
{
  return SystemTools::HasEnv(key.c_str());
}

558 559 560
#if KWSYS_CXX_HAS_UNSETENV
/* unsetenv("A") removes A from the environment.
   On older platforms it returns void instead of int.  */
561
static int kwsysUnPutEnv(const std::string& env)
562
{
563
  size_t pos = env.find('=');
564
  if (pos != std::string::npos) {
565
    std::string name = env.substr(0, pos);
566
    unsetenv(name.c_str());
567
  } else {
568
    unsetenv(env.c_str());
569
  }
570 571
  return 0;
}
572

573 574 575
#elif defined(__CYGWIN__) || defined(__GLIBC__)
/* putenv("A") removes A from the environment.  It must not put the
   memory in the environment because it does not have any "=" syntax.  */
576
static int kwsysUnPutEnv(const std::string& env)
577
{
578
  int err = 0;
579
  size_t pos = env.find('=');
580
  size_t const len = pos == std::string::npos ? env.size() : pos;
581 582 583
  size_t const sz = len + 1;
  char local_buf[256];
  char* buf = sz > sizeof(local_buf) ? (char*)malloc(sz) : local_buf;
584
  if (!buf) {
585
    return -1;
586
  }
587
  strncpy(buf, env.c_str(), len);
588
  buf[len] = 0;
589
  if (putenv(buf) < 0 && errno != EINVAL) {
590
    err = errno;
591 592
  }
  if (buf != local_buf) {
593
    free(buf);
594 595
  }
  if (err) {
596 597
    errno = err;
    return -1;
598
  }
599 600 601
  return 0;
}

602 603 604 605 606 607 608 609
#elif defined(_WIN32)
/* putenv("A=") places "A=" in the environment, which is as close to
   removal as we can get with the putenv API.  We have to leak the
   most recent value placed in the environment for each variable name
   on program exit in case exit routines access it.  */

static kwsysEnvSet kwsysUnPutEnvSet;

610
static int kwsysUnPutEnv(std::string const& env)
611
{
612 613
  std::wstring wEnv = Encoding::ToWide(env);
  size_t const pos = wEnv.find('=');
614
  size_t const len = pos == std::string::npos ? wEnv.size() : pos;
615
  wEnv.resize(len + 1, L'=');
616
  wchar_t* newEnv = _wcsdup(wEnv.c_str());
617
  if (!newEnv) {
618
    return -1;
619
  }
620 621
  kwsysEnvSet::Free oldEnv(kwsysUnPutEnvSet.Release(newEnv));
  kwsysUnPutEnvSet.insert(newEnv);
622
  return _wputenv(newEnv);
623 624
}

625 626
#else
/* Manipulate the "environ" global directly.  */
627
static int kwsysUnPutEnv(const std::string& env)
628
{
629
  size_t pos = env.find('=');
630
  size_t const len = pos == std::string::npos ? env.size() : pos;
631 632
  int in = 0;
  int out = 0;
633 634 635
  while (environ[in]) {
    if (strlen(environ[in]) > len && environ[in][len] == '=' &&
        strncmp(env.c_str(), environ[in], len) == 0) {
636
      ++in;
637
    } else {
638 639
      environ[out++] = environ[in++];
    }
640 641
  }
  while (out < in) {
642
    environ[out++] = 0;
643
  }
644 645
  return 0;
}
646
#endif
647 648 649 650 651

#if KWSYS_CXX_HAS_SETENV

/* setenv("A", "B", 1) will set A=B in the environment and makes its
   own copies of the strings.  */
652
bool SystemTools::PutEnv(const std::string& env)
653
{
654
  size_t pos = env.find('=');
655
  if (pos != std::string::npos) {
656 657
    std::string name = env.substr(0, pos);
    return setenv(name.c_str(), env.c_str() + pos + 1, 1) == 0;
658
  } else {
659
    return kwsysUnPutEnv(env) == 0;
660
  }
661
}
662

663
bool SystemTools::UnPutEnv(const std::string& env)
664
{
665
  return kwsysUnPutEnv(env) == 0;
666 667
}

668 669 670 671 672 673 674 675 676
#else

/* putenv("A=B") will set A=B in the environment.  Most putenv implementations
   put their argument directly in the environment.  They never free the memory
   on program exit.  Keep an active set of pointers to memory we allocate and
   pass to putenv, one per environment key.  At program exit remove any
   environment values that may still reference memory we allocated.  Then free
   the memory.  This will not affect any environment values we never set.  */

677 678 679
#  ifdef __INTEL_COMPILER
#    pragma warning disable 444 /* base has non-virtual destructor */
#  endif
680

681
class kwsysEnv : public kwsysEnvSet
682 683 684
{
public:
  ~kwsysEnv()
685 686
  {
    for (iterator i = this->begin(); i != this->end(); ++i) {
687
#  if defined(_WIN32)
688
      const std::string s = Encoding::ToNarrow(*i);
689
      kwsysUnPutEnv(s);
690
#  else
691
      kwsysUnPutEnv(*i);
692
#  endif
693
      free(const_cast<envchar*>(*i));
694
    }
695
  }
696
  bool Put(const char* env)
697
  {
698
#  if defined(_WIN32)
699 700
    const std::wstring wEnv = Encoding::ToWide(env);
    wchar_t* newEnv = _wcsdup(wEnv.c_str());
701
#  else
702
    char* newEnv = strdup(env);
703
#  endif
704
    Free oldEnv(this->Release(newEnv));
705
    this->insert(newEnv);
706
#  if defined(_WIN32)
707
    return _wputenv(newEnv) == 0;
708
#  else
709
    return putenv(newEnv) == 0;
710
#  endif
711
  }
712
  bool UnPut(const char* env)
713
  {
714
#  if defined(_WIN32)
715 716
    const std::wstring wEnv = Encoding::ToWide(env);
    Free oldEnv(this->Release(wEnv.c_str()));
717
#  else
718
    Free oldEnv(this->Release(env));
719
#  endif
720
    return kwsysUnPutEnv(env) == 0;
721
  }
722 723 724 725
};

static kwsysEnv kwsysEnvInstance;

726
bool SystemTools::PutEnv(const std::string& env)
727
{
728
  return kwsysEnvInstance.Put(env.c_str());
729 730
}

731
bool SystemTools::UnPutEnv(const std::string& env)
732
{
733
  return kwsysEnvInstance.UnPut(env.c_str());
734 735 736 737
}

#endif

738 739
const char* SystemTools::GetExecutableExtension()
{
Bill Hoffman's avatar
Bill Hoffman committed
740
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__VMS)
741 742 743
  return ".exe";
#else
  return "";
744
#endif
745 746
}

747
FILE* SystemTools::Fopen(const std::string& file, const char* mode)
748 749
{
#ifdef _WIN32
750
  return _wfopen(Encoding::ToWindowsExtendedPath(file).c_str(),
751 752
                 Encoding::ToWide(mode).c_str());
#else
753
  return fopen(file.c_str(), mode);
754 755
#endif
}
756

757
bool SystemTools::MakeDirectory(const char* path, const mode_t* mode)
758
{
759
  if (!path) {
Bill Hoffman's avatar
Bill Hoffman committed
760
    return false;
761
  }
762
  return SystemTools::MakeDirectory(std::string(path), mode);
763 764
}

765
bool SystemTools::MakeDirectory(const std::string& path, const mode_t* mode)
766
{
767
  if (SystemTools::PathExists(path)) {
768
    return SystemTools::FileIsDirectory(path);
769 770
  }
  if (path.empty()) {
771
    return false;
772
  }
773
  std::string dir = path;
774 775
  SystemTools::ConvertToUnixSlashes(dir);

776 777
  std::string::size_type pos = 0;
  std::string topdir;
778
  while ((pos = dir.find('/', pos)) != std::string::npos) {
779
    topdir = dir.substr(0, pos);
780

781
    if (Mkdir(topdir) == 0 && mode != KWSYS_NULLPTR) {
782 783 784 785
      SystemTools::SetPermissions(topdir, *mode);
    }

    ++pos;
786
  }
787
  topdir = dir;
788
  if (Mkdir(topdir) != 0) {
789 790 791 792
    // There is a bug in the Borland Run time library which makes MKDIR
    // return EACCES when it should return EEXISTS
    // if it is some other error besides directory exists
    // then return false
793
    if ((errno != EEXIST)
794
#ifdef __BORLANDC__
795 796
        && (errno != EACCES)
#endif
797
    ) {
798 799
      return false;
    }
800
  } else if (mode != KWSYS_NULLPTR) {
801
    SystemTools::SetPermissions(topdir, *mode);
802
  }
803

804 805 806 807 808
  return true;
}

// replace replace with with as many times as it shows up in source.
// write the result into source.
809 810 811
void SystemTools::ReplaceString(std::string& source,
                                const std::string& replace,
                                const std::string& with)
812 813
{
  // do while hangs if replaceSize is 0
814
  if (replace.empty()) {
815
    return;
816
  }
817 818 819 820

  SystemTools::ReplaceString(source, replace.c_str(), replace.size(), with);
}

821
void SystemTools::ReplaceString(std::string& source, const char* replace,
822 823 824
                                const char* with)
{
  // do while hangs if replaceSize is 0
825
  if (!*replace) {
826
    return;
827
  }
828

829 830
  SystemTools::ReplaceString(source, replace, strlen(replace),
                             with ? with : "");
831 832
}

833 834
void SystemTools::ReplaceString(std::string& source, const char* replace,
                                size_t replaceSize, const std::string& with)
835
{
836 837
  const char* src = source.c_str();
  char* searchPos = const_cast<char*>(strstr(src, replace));
838

839
  // get out quick if string is not found
840
  if (!searchPos) {
841
    return;
842
  }
Ken Martin's avatar
Ken Martin committed
843 844

  // perform replacements until done
845 846
  char* orig = strdup(src);
  char* currentPos = orig;
Ken Martin's avatar
Ken Martin committed
847
  searchPos = searchPos - src + orig;
848

Ken Martin's avatar
Ken Martin committed
849
  // initialize the result
850 851
  source.erase(source.begin(), source.end());
  do {
Ken Martin's avatar
Ken Martin committed
852 853 854 855
    *searchPos = '\0';
    source += currentPos;
    currentPos = searchPos + replaceSize;
    // replace
856
    source += with;
857 858
    searchPos = strstr(currentPos, replace);
  } while (searchPos);
Ken Martin's avatar
Ken Martin committed
859 860 861 862

  // copy any trailing text
  source += currentPos;
  free(orig);
863 864
}

865 866
#if defined(_WIN32) && !defined(__CYGWIN__)

867 868 869 870 871 872 873
#  if defined(KEY_WOW64_32KEY) && defined(KEY_WOW64_64KEY)
#    define KWSYS_ST_KEY_WOW64_32KEY KEY_WOW64_32KEY
#    define KWSYS_ST_KEY_WOW64_64KEY KEY_WOW64_64KEY
#  else
#    define KWSYS_ST_KEY_WOW64_32KEY 0x0200
#    define KWSYS_ST_KEY_WOW64_64KEY 0x0100
#  endif
874

875
static bool SystemToolsParseRegistryKey(const std::string& key,
876
                                        HKEY& primaryKey, std::string& second,
877
                                        std::string& valuename)
878
{
879
  std::string primary = key;
880

881
  size_t start = primary.find('\\');
882
  if (start == std::string::npos) {
883
    return false;
884
  }
885

886
  size_t valuenamepos = primary.find(';');
887 888 889
  if (valuenamepos != std::string::npos) {
    valuename = primary.substr(valuenamepos + 1);
  }
890

891
  second = primary.substr(start + 1, valuenamepos - start - 1);
892 893
  primary = primary.substr(0, start);

894
  if (primary == "HKEY_CURRENT_USER") {
895
    primaryKey = HKEY_CURRENT_USER;
896 897
  }
  if (primary == "HKEY_CURRENT_CONFIG") {
898
    primaryKey = HKEY_CURRENT_CONFIG;
899 900
  }
  if (primary == "HKEY_CLASSES_ROOT") {
901
    primaryKey = HKEY_CLASSES_ROOT;
902 903
  }
  if (primary == "HKEY_LOCAL_MACHINE") {
904
    primaryKey = HKEY_LOCAL_MACHINE;
905 906
  }
  if (primary == "HKEY_USERS") {
907
    primaryKey = HKEY_USERS;
908
  }
909 910 911 912

  return true;
}

913 914 915
static DWORD SystemToolsMakeRegistryMode(DWORD mode,
                                         SystemTools::KeyWOW64 view)
{
916
  // only add the modes when on a system that supports Wow64.
917 918 919
  static FARPROC wow64p =
    GetProcAddress(GetModuleHandleW(L"kernel32"), "IsWow64Process");
  if (wow64p == NULL) {
920
    return mode;
921
  }
922

923
  if (view == SystemTools::KeyWOW64_32) {
924
    return mode | KWSYS_ST_KEY_WOW64_32KEY;
925
  } else if (view == SystemTools::KeyWOW64_64) {
926
    return mode | KWSYS_ST_KEY_WOW64_64KEY;
927
  }
928 929 930 931
  return mode;
}
#endif

932
#if defined(_WIN32) && !defined(__CYGWIN__)
933 934 935
bool SystemTools::GetRegistrySubKeys(const std::string& key,
                                     std::vector<std::string>& subkeys,
                                     KeyWOW64 view)
936 937
{
  HKEY primaryKey = HKEY_CURRENT_USER;
938 939
  std::string second;
  std::string valuename;
940
  if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) {
941
    return false;
942
  }
943 944

  HKEY hKey;
945 946 947
  if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0,
                    SystemToolsMakeRegistryMode(KEY_READ, view),
                    &hKey) != ERROR_SUCCESS) {
948
    return false;
949
  } else {
950
    wchar_t name[1024];
951
    DWORD dwNameSize = sizeof(name) / sizeof(name[0]);
952 953

    DWORD i = 0;
954
    while (RegEnumKeyW(hKey, i, name, dwNameSize) == ERROR_SUCCESS) {
955
      subkeys.push_back(Encoding::ToNarrow(name));
956
      ++i;
957
    }
958 959

    RegCloseKey(hKey);
960
  }
961 962 963 964

  return true;
}
#else
965
bool SystemTools::GetRegistrySubKeys(const std::string&,
966
                                     std::vector<std::string>&, KeyWOW64)
967 968 969 970 971
{
  return false;
}
#endif

972
// Read a registry value.
973
// Example :
974 975 976 977 978 979
//      HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath
//      =>  will return the data of the "default" value of the key
//      HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root
//      =>  will return the data of the "Root" value of the key

#if defined(_WIN32) && !defined(__CYGWIN__)
980
bool SystemTools::ReadRegistryValue(const std::string& key, std::string& value,
981
                                    KeyWOW64 view)
982
{
983
  bool valueset = false;
984
  HKEY primaryKey = HKEY_CURRENT_USER;
985 986
  std::string second;
  std::string valuename;
987
  if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) {
988
    return false;
989
  }
990 991

  HKEY hKey;
992 993 994
  if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0,
                    SystemToolsMakeRegistryMode(KEY_READ, view),
                    &hKey) != ERROR_SUCCESS) {
995
    return false;
996
  } else {
997