SystemTools.cxx 135 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 57
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.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

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

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

122 123 124 125 126
#ifdef _MSC_VER
#include <sys/utime.h>
#else
#include <utime.h>
#endif
Alexander Neundorf's avatar
 
Alexander Neundorf committed
127

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

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

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

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

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

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

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

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

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

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

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

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

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

339
namespace KWSYS_NAMESPACE {
340

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
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());
}

551 552 553 554 555
//----------------------------------------------------------------------------

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

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

597 598 599 600 601 602 603 604
#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;

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

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

//----------------------------------------------------------------------------

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

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

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

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

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

static kwsysEnv kwsysEnvInstance;

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

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

#endif

//----------------------------------------------------------------------------

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

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

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

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

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

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

813
void SystemTools::ReplaceString(std::string& source, const char* replace,
814 815 816
                                const char* with)
{
  // do while hangs if replaceSize is 0
817
  if (!*replace) {
818
    return;
819
  }
820

821 822
  SystemTools::ReplaceString(source, replace, strlen(replace),
                             with ? with : "");
823 824
}

825 826
void SystemTools::ReplaceString(std::string& source, const char* replace,
                                size_t replaceSize, const std::string& with)
827
{
828 829
  const char* src = source.c_str();
  char* searchPos = const_cast<char*>(strstr(src, replace));
830

831
  // get out quick if string is not found
832
  if (!searchPos) {
833
    return;
834
  }
Ken Martin's avatar
Ken Martin committed
835 836

  // perform replacements until done
837 838
  char* orig = strdup(src);
  char* currentPos = orig;
Ken Martin's avatar
Ken Martin committed
839
  searchPos = searchPos - src + orig;
840

Ken Martin's avatar
Ken Martin committed
841
  // initialize the result
842 843
  source.erase(source.begin(), source.end());
  do {
Ken Martin's avatar
Ken Martin committed
844 845 846 847
    *searchPos = '\0';
    source += currentPos;
    currentPos = searchPos + replaceSize;
    // replace
848
    source += with;
849 850
    searchPos = strstr(currentPos, replace);
  } while (searchPos);
Ken Martin's avatar
Ken Martin committed
851 852 853 854

  // copy any trailing text
  source += currentPos;
  free(orig);
855 856
}

857
#if defined(KEY_WOW64_32KEY) && defined(KEY_WOW64_64KEY)
858 859
#define KWSYS_ST_KEY_WOW64_32KEY KEY_WOW64_32KEY
#define KWSYS_ST_KEY_WOW64_64KEY KEY_WOW64_64KEY
860
#else
861 862
#define KWSYS_ST_KEY_WOW64_32KEY 0x0200
#define KWSYS_ST_KEY_WOW64_64KEY 0x0100
863 864 865
#endif

#if defined(_WIN32) && !defined(__CYGWIN__)
Brad King's avatar
Brad King committed
866
static bool SystemToolsParseRegistryKey(const std::string& key,
867
                                        HKEY& primaryKey, std::string& second,
Brad King's avatar
Brad King committed
868
                                        std::string& valuename)
869
{
Brad King's avatar
Brad King committed
870
  std::string primary = key;
871

872
  size_t start = primary.find('\\');
873
  if (start == std::string::npos) {
874
    return false;
875
  }
876

877
  size_t valuenamepos = primary.find(';');
878 879 880
  if (valuenamepos != std::string::npos) {
    valuename = primary.substr(valuenamepos + 1);
  }
881

882
  second = primary.substr(start + 1, valuenamepos - start - 1);