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
#if defined(_WIN32) && (defined(_MSC_VER) || defined(__WATCOMC__) ||          \
                        defined(__BORLANDC__) || defined(__MINGW32__))
#define KWSYS_WINDOWS_DIRS
12
#else
13 14 15
#if defined(__SUNPRO_CC)
#include <fcntl.h>
#endif
16 17
#endif

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

26
#include <fstream>
27
#include <iostream>
Brad King's avatar
Brad King committed
28
#include <set>
29
#include <sstream>
30
#include <vector>
31

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

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

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

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

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

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

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

84 85
// Windows API.
#if defined(_WIN32)
86 87 88 89 90 91 92 93 94 95 96
#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
#elif defined(__CYGWIN__)
#include <windows.h>
#undef _WIN32
97 98
#endif

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

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

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

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

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

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

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

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

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

// 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.
184
static inline char* realpath(const char* path, char* resolved_path)
185 186 187 188
{
  const size_t maxlen = KWSYS_SYSTEMTOOLS_MAXPATH;
  snprintf(resolved_path, maxlen, "%s", path);
  BPath normalized(resolved_path, NULL, true);
189 190 191 192
  const char* resolved = normalized.Path();
  if (resolved != NULL) // NULL == No such file.
  {
    if (snprintf(resolved_path, maxlen, "%s", resolved) < maxlen) {
193 194
      return resolved_path;
    }
195 196
  }
  return NULL; // something went wrong.
197 198 199
}
#endif

200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
#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

215
#ifdef KWSYS_WINDOWS_DIRS
216 217
#include <wctype.h>

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

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

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

Brad King's avatar
Brad King committed
304
inline int Chdir(const std::string& dir)
305
{
306
  return chdir(dir.c_str());
307
}
308
inline void Realpath(const std::string& path, std::string& resolved_path,
309
                     std::string* errorMessage = KWSYS_NULLPTR)
310
{
311
  char resolved_name[KWSYS_SYSTEMTOOLS_MAXPATH];
312

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

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

332 333
#if !defined(_WIN32) && defined(__COMO__)
// Hack for como strict mode to avoid defining _SVID_SOURCE or _BSD_SOURCE.
334 335 336 337 338 339 340
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;
341 342
}
#endif
343

344
namespace KWSYS_NAMESPACE {
345

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

360
class SystemToolsTranslationMap : public std::map<std::string, std::string>
361 362 363
{
};

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

371 372 373
/* Order by environment key only (VAR from VAR=VALUE).  */
struct kwsysEnvCompare
{
374 375
  bool operator()(const envchar* l, const envchar* r) const
  {
376 377 378
#if defined(_WIN32)
    const wchar_t* leq = wcschr(l, L'=');
    const wchar_t* req = wcschr(r, L'=');
379 380 381 382 383 384 385
    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;
    }
386
#else
387 388
    const char* leq = strchr(l, '=');
    const char* req = strchr(r, '=');
389 390 391 392 393 394
    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;
395
    }
396 397
#endif
  }
398 399
};

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

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

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

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

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

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

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

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

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

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

Brad King's avatar
Brad King committed
511
const char* SystemTools::GetEnv(const std::string& key)
512
{
513
  return SystemTools::GetEnvImpl(key.c_str());
514 515
}

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

Brad King's avatar
Brad King committed
535
bool SystemTools::GetEnv(const std::string& key, std::string& result)
536 537 538 539
{
  return SystemTools::GetEnv(key.c_str(), result);
}

540 541 542 543 544 545 546 547
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
548
  return v != KWSYS_NULLPTR;
549 550 551 552 553 554 555
}

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

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

571 572 573
#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.  */
Brad King's avatar
Brad King committed
574
static int kwsysUnPutEnv(const std::string& env)
Bill Hoffman's avatar
Bill Hoffman committed
575
{
576
  int err = 0;
577
  size_t pos = env.find('=');
578
  size_t const len = pos == std::string::npos ? env.size() : pos;
579 580 581
  size_t const sz = len + 1;
  char local_buf[256];
  char* buf = sz > sizeof(local_buf) ? (char*)malloc(sz) : local_buf;
582
  if (!buf) {
583
    return -1;
584
  }
585
  strncpy(buf, env.c_str(), len);
586
  buf[len] = 0;
587
  if (putenv(buf) < 0 && errno != EINVAL) {
588
    err = errno;
589 590
  }
  if (buf != local_buf) {
591
    free(buf);
592 593
  }
  if (err) {
594 595
    errno = err;
    return -1;
596
  }
597 598 599
  return 0;
}

600 601 602 603 604 605 606 607
#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;

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

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

#if KWSYS_CXX_HAS_SETENV

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

Brad King's avatar
Brad King committed
661
bool SystemTools::UnPutEnv(const std::string& env)
662
{
663
  return kwsysUnPutEnv(env) == 0;
664 665
}

666 667 668 669 670 671 672 673 674
#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.  */

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

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

static kwsysEnv kwsysEnvInstance;

Brad King's avatar
Brad King committed
724
bool SystemTools::PutEnv(const std::string& env)
725
{
726
  return kwsysEnvInstance.Put(env.c_str());
727 728
}

Brad King's avatar
Brad King committed
729
bool SystemTools::UnPutEnv(const std::string& env)
730
{
731
  return kwsysEnvInstance.UnPut(env.c_str());
732 733 734 735
}

#endif

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

Brad King's avatar
Brad King committed
745
FILE* SystemTools::Fopen(const std::string& file, const char* mode)
746 747
{
#ifdef _WIN32
748
  return _wfopen(Encoding::ToWindowsExtendedPath(file).c_str(),
749 750
                 Encoding::ToWide(mode).c_str());
#else
751
  return fopen(file.c_str(), mode);
752 753
#endif
}
754

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

763
bool SystemTools::MakeDirectory(const std::string& path, const mode_t* mode)
764
{
765
  if (SystemTools::PathExists(path)) {
766
    return SystemTools::FileIsDirectory(path);
767 768
  }
  if (path.empty()) {
769
    return false;
770
  }
Brad King's avatar
Brad King committed
771
  std::string dir = path;
772 773
  SystemTools::ConvertToUnixSlashes(dir);

Brad King's avatar
Brad King committed
774 775
  std::string::size_type pos = 0;
  std::string topdir;
776
  while ((pos = dir.find('/', pos)) != std::string::npos) {
777
    topdir = dir.substr(0, pos);
778

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

    ++pos;
784
  }
785
  topdir = dir;
786
  if (Mkdir(topdir) != 0) {
787 788 789 790
    // 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
791
    if ((errno != EEXIST)
792
#ifdef __BORLANDC__
793 794
        && (errno != EACCES)
#endif
795
          ) {
796 797
      return false;
    }
798
  } else if (mode != KWSYS_NULLPTR) {
799
    SystemTools::SetPermissions(topdir, *mode);
800
  }
801

802 803 804 805 806
  return true;
}

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

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

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

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

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

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

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

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

  // copy any trailing text
  source += currentPos;
  free(orig);
861 862
}

863 864
#if defined(_WIN32) && !defined(__CYGWIN__)

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

Brad King's avatar
Brad King committed
873
static bool SystemToolsParseRegistryKey(const std::string& key,
874
                                        HKEY& primaryKey, std::string& second,
Brad King's avatar
Brad King committed
875
                                        std::string& valuename)
876
{
Brad King's avatar
Brad King committed