SystemTools.cxx 132 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 23
#include KWSYS_HEADER(FStream.hxx)
#include KWSYS_HEADER(Encoding.hxx)
24

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

171
#if defined(__BEOS__) && !defined(__ZETA__)
172 173 174 175 176 177 178 179 180 181
#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.
182
static inline char* realpath(const char* path, char* resolved_path)
183 184 185 186
{
  const size_t maxlen = KWSYS_SYSTEMTOOLS_MAXPATH;
  snprintf(resolved_path, maxlen, "%s", path);
  BPath normalized(resolved_path, NULL, true);
187 188 189 190
  const char* resolved = normalized.Path();
  if (resolved != NULL) // NULL == No such file.
  {
    if (snprintf(resolved_path, maxlen, "%s", resolved) < maxlen) {
191 192
      return resolved_path;
    }
193 194
  }
  return NULL; // something went wrong.
195 196 197
}
#endif

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

213
#ifdef KWSYS_WINDOWS_DIRS
214 215
#include <wctype.h>

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

    resolved_path = "";
276
  } else {
277
    resolved_path = path;
278
  }
279
}
280 281
#else
#include <sys/types.h>
282

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

Brad King's avatar
Brad King committed
298
inline int Chdir(const std::string& dir)
299
{
300
  return chdir(dir.c_str());
301
}
302
inline void Realpath(const std::string& path, std::string& resolved_path,
Brad King's avatar
Brad King committed
303
                     std::string* errorMessage = 0)
304
{
305
  char resolved_name[KWSYS_SYSTEMTOOLS_MAXPATH];
306

307
  errno = 0;
308 309
  char* ret = realpath(path.c_str(), resolved_name);
  if (ret) {
310
    resolved_path = ret;
311 312
  } else if (errorMessage) {
    if (errno) {
313
      *errorMessage = strerror(errno);
314
    } else {
315
      *errorMessage = "Unknown error.";
316
    }
317 318

    resolved_path = "";
319
  } else {
320 321
    // if path resolution fails, return what was passed in
    resolved_path = path;
322
  }
323
}
324 325
#endif

326 327
#if !defined(_WIN32) && defined(__COMO__)
// Hack for como strict mode to avoid defining _SVID_SOURCE or _BSD_SOURCE.
328 329 330 331 332 333 334
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;
335 336
}
#endif
337

338
namespace KWSYS_NAMESPACE {
339

340 341 342 343 344
double SystemTools::GetTime(void)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
  FILETIME ft;
  GetSystemTimeAsFileTime(&ft);
345 346
  return (429.4967296 * ft.dwHighDateTime + 0.0000001 * ft.dwLowDateTime -
          11644473600.0);
347 348 349
#else
  struct timeval t;
  gettimeofday(&t, 0);
350
  return 1.0 * double(t.tv_sec) + 0.000001 * double(t.tv_usec);
351 352 353
#endif
}

354
class SystemToolsTranslationMap : public std::map<std::string, std::string>
355 356 357
{
};

358
/* Type of character storing the environment.  */
359 360 361
#if defined(_WIN32)
typedef wchar_t envchar;
#else
362
typedef char envchar;
363
#endif
364

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

394
class kwsysEnvSet : public std::set<const envchar*, kwsysEnvCompare>
395 396 397 398
{
public:
  class Free
  {
399
    const envchar* Env;
400

401
  public:
402 403 404 405
    Free(const envchar* env)
      : Env(env)
    {
    }
406
    ~Free() { free(const_cast<envchar*>(this->Env)); }
407 408
  };

409
  const envchar* Release(const envchar* env)
410
  {
411
    const envchar* old = 0;
412
    iterator i = this->find(env);
413
    if (i != this->end()) {
414 415 416
      old = *i;
      this->erase(i);
    }
417 418
    return old;
  }
419 420
};

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

436 437 438 439
class SystemToolsPathCaseMap
  : public std::map<std::string, std::string, SystemToolsPathCaseCmp>
{
};
440

441 442 443
class SystemToolsEnvMap : public std::map<std::string, std::string>
{
};
444 445
#endif

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

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

484
const char* SystemTools::GetEnvImpl(const char* key)
Brad King's avatar
Brad King committed
485
{
486
  const char* v = 0;
487 488
#if defined(_WIN32)
  std::string env;
489
  if (SystemTools::GetEnv(key, env)) {
490 491 492
    std::string& menv = (*SystemTools::EnvMap)[key];
    menv = env;
    v = menv.c_str();
493
  }
494
#else
495
  v = getenv(key);
496
#endif
497
  return v;
Brad King's avatar
Brad King committed
498 499
}

500 501 502 503 504
const char* SystemTools::GetEnv(const char* key)
{
  return SystemTools::GetEnvImpl(key);
}

Brad King's avatar
Brad King committed
505
const char* SystemTools::GetEnv(const std::string& key)
506
{
507
  return SystemTools::GetEnvImpl(key.c_str());
508 509
}

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

Brad King's avatar
Brad King committed
529
bool SystemTools::GetEnv(const std::string& key, std::string& result)
530 531 532 533
{
  return SystemTools::GetEnv(key.c_str(), result);
}

534 535 536 537 538 539 540 541 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
  return v != 0;
}

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

550 551 552
#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
553
static int kwsysUnPutEnv(const std::string& env)
554
{
555
  size_t pos = env.find('=');
556
  if (pos != std::string::npos) {
557
    std::string name = env.substr(0, pos);
558
    unsetenv(name.c_str());
559
  } else {
560
    unsetenv(env.c_str());
561
  }
562 563
  return 0;
}
564

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

594 595 596 597 598 599 600 601
#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;

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

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

#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
644
bool SystemTools::PutEnv(const std::string& env)
645
{
646
  size_t pos = env.find('=');
647
  if (pos != std::string::npos) {
648 649
    std::string name = env.substr(0, pos);
    return setenv(name.c_str(), env.c_str() + pos + 1, 1) == 0;
650
  } else {
651
    return kwsysUnPutEnv(env) == 0;
652
  }
Bill Hoffman's avatar
Bill Hoffman committed
653
}
654

Brad King's avatar
Brad King committed
655
bool SystemTools::UnPutEnv(const std::string& env)
656
{
657
  return kwsysUnPutEnv(env) == 0;
658 659
}

660 661 662 663 664 665 666 667 668
#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.  */

669 670 671
#ifdef __INTEL_COMPILER
#pragma warning disable 444 /* base has non-virtual destructor */
#endif
672

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

static kwsysEnv kwsysEnvInstance;

Brad King's avatar
Brad King committed
718
bool SystemTools::PutEnv(const std::string& env)
719
{
720
  return kwsysEnvInstance.Put(env.c_str());
721 722
}

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

#endif

730 731
const char* SystemTools::GetExecutableExtension()
{
Bill Hoffman's avatar
Bill Hoffman committed
732
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__VMS)
733 734 735
  return ".exe";
#else
  return "";
736
#endif
737 738
}

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

bool SystemTools::MakeDirectory(const char* path)
{
751
  if (!path) {
Bill Hoffman's avatar
Bill Hoffman committed
752
    return false;
753
  }
Brad King's avatar
Brad King committed
754
  return SystemTools::MakeDirectory(std::string(path));
755 756
}

Brad King's avatar
Brad King committed
757
bool SystemTools::MakeDirectory(const std::string& path)
758
{
759
  if (SystemTools::PathExists(path)) {
760
    return SystemTools::FileIsDirectory(path);
761 762
  }
  if (path.empty()) {
763
    return false;
764
  }
Brad King's avatar
Brad King committed
765
  std::string dir = path;
766 767
  SystemTools::ConvertToUnixSlashes(dir);

Brad King's avatar
Brad King committed
768 769
  std::string::size_type pos = 0;
  std::string topdir;
770
  while ((pos = dir.find('/', pos)) != std::string::npos) {
771
    topdir = dir.substr(0, pos);
772
    Mkdir(topdir);
773
    pos++;
774
  }
775
  topdir = dir;
776
  if (Mkdir(topdir) != 0) {
777 778 779 780
    // 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
781
    if ((errno != EEXIST)
782
#ifdef __BORLANDC__
783 784
        && (errno != EACCES)
#endif
785
          ) {
786 787
      return false;
    }
788
  }
789 790 791 792 793
  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
794 795 796
void SystemTools::ReplaceString(std::string& source,
                                const std::string& replace,
                                const std::string& with)
797 798
{
  // do while hangs if replaceSize is 0
799
  if (replace.empty()) {
800
    return;
801
  }
802 803 804 805

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

806
void SystemTools::ReplaceString(std::string& source, const char* replace,
807 808 809
                                const char* with)
{
  // do while hangs if replaceSize is 0
810
  if (!*replace) {
811
    return;
812
  }
813

814 815
  SystemTools::ReplaceString(source, replace, strlen(replace),
                             with ? with : "");
816 817
}

818 819
void SystemTools::ReplaceString(std::string& source, const char* replace,
                                size_t replaceSize, const std::string& with)
820
{
821 822
  const char* src = source.c_str();
  char* searchPos = const_cast<char*>(strstr(src, replace));
823

824
  // get out quick if string is not found
825
  if (!searchPos) {
826
    return;
827
  }
Ken Martin's avatar
Ken Martin committed
828 829

  // perform replacements until done
830 831
  char* orig = strdup(src);
  char* currentPos = orig;
Ken Martin's avatar
Ken Martin committed
832
  searchPos = searchPos - src + orig;
833

Ken Martin's avatar
Ken Martin committed
834
  // initialize the result
835 836
  source.erase(source.begin(), source.end());
  do {
Ken Martin's avatar
Ken Martin committed
837 838 839 840
    *searchPos = '\0';
    source += currentPos;
    currentPos = searchPos + replaceSize;
    // replace
841
    source += with;
842 843
    searchPos = strstr(currentPos, replace);
  } while (searchPos);
Ken Martin's avatar
Ken Martin committed
844 845 846 847

  // copy any trailing text
  source += currentPos;
  free(orig);
848 849
}

850 851
#if defined(_WIN32) && !defined(__CYGWIN__)

852
#if defined(KEY_WOW64_32KEY) && defined(KEY_WOW64_64KEY)
853 854
#define KWSYS_ST_KEY_WOW64_32KEY KEY_WOW64_32KEY
#define KWSYS_ST_KEY_WOW64_64KEY KEY_WOW64_64KEY
855
#else
856 857
#define KWSYS_ST_KEY_WOW64_32KEY 0x0200
#define KWSYS_ST_KEY_WOW64_64KEY 0x0100
858 859
#endif

Brad King's avatar
Brad King committed
860
static bool SystemToolsParseRegistryKey(const std::string& key,
861
                                        HKEY& primaryKey, std::string& second,
Brad King's avatar
Brad King committed
862
                                        std::string& valuename)
863
{
Brad King's avatar
Brad King committed
864
  std::string primary = key;
865

866
  size_t start = primary.find('\\');
867
  if (start == std::string::npos) {
868
    return false;
869
  }
870

871
  size_t valuenamepos = primary.find(';');
872 873 874
  if (valuenamepos != std::string::npos) {
    valuename = primary.substr(valuenamepos + 1);
  }