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

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

Kitware Robot's avatar
Kitware Robot committed
18
19
20
21
#include "kwsysPrivate.h"
#include KWSYS_HEADER(RegularExpression.hxx)
#include KWSYS_HEADER(SystemTools.hxx)
#include KWSYS_HEADER(Directory.hxx)
Kitware Robot's avatar
Kitware Robot committed
22
#include KWSYS_HEADER(FStream.hxx)
Kitware Robot's avatar
Kitware Robot committed
23
#include KWSYS_HEADER(Encoding.h)
Kitware Robot's avatar
Kitware Robot committed
24
#include KWSYS_HEADER(Encoding.hxx)
Kitware Robot's avatar
Kitware Robot committed
25

Kitware Robot's avatar
Kitware Robot committed
26
#include <fstream>
Kitware Robot's avatar
Kitware Robot committed
27
#include <iostream>
Kitware Robot's avatar
Kitware Robot committed
28
#include <set>
Kitware Robot's avatar
Kitware Robot committed
29
#include <sstream>
Kitware Robot's avatar
Kitware Robot committed
30
#include <vector>
Kitware Robot's avatar
Kitware Robot committed
31
32
33
34

// Work-around CMake dependency scanning limitation.  This must
// duplicate the above list of headers.
#if 0
Kitware Robot's avatar
Kitware Robot committed
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"
Kitware Robot's avatar
Kitware Robot committed
40
41
42
#endif

#ifdef _MSC_VER
Kitware Robot's avatar
Kitware Robot committed
43
#pragma warning(disable : 4786)
Kitware Robot's avatar
Kitware Robot committed
44
45
46
#endif

#if defined(__sgi) && !defined(__GNUC__)
Kitware Robot's avatar
Kitware Robot committed
47
#pragma set woff 1375 /* base class destructor not virtual */
Kitware Robot's avatar
Kitware Robot committed
48
49
50
51
52
#endif

#include <ctype.h>
#include <errno.h>
#ifdef __QNX__
Kitware Robot's avatar
Kitware Robot committed
53
#include <malloc.h> /* for malloc/free on QNX */
Kitware Robot's avatar
Kitware Robot committed
54
55
56
57
58
59
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

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

Kitware Robot's avatar
Kitware Robot committed
64
#ifdef _MSC_VER
Kitware Robot's avatar
Kitware Robot committed
65
#define umask _umask // Note this is still umask on Borland
Kitware Robot's avatar
Kitware Robot committed
66
67
#endif

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

// Windows API.
#if defined(_WIN32)
Kitware Robot's avatar
Kitware Robot committed
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
Kitware Robot's avatar
Kitware Robot committed
97
98
99
#endif

#if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
Kitware Robot's avatar
Kitware Robot committed
100
extern char** environ;
Kitware Robot's avatar
Kitware Robot committed
101
102
103
#endif

#ifdef __CYGWIN__
Kitware Robot's avatar
Kitware Robot committed
104
#include <sys/cygwin.h>
Kitware Robot's avatar
Kitware Robot committed
105
106
107
108
#endif

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

#define VTK_URL_PROTOCOL_REGEX "([a-zA-Z0-9]*)://(.*)"
Kitware Robot's avatar
Kitware Robot committed
119
120
121
#define VTK_URL_REGEX                                                         \
  "([a-zA-Z0-9]*)://(([A-Za-z0-9]+)(:([^:@]+))?@)?([^:@/]+)(:([0-9]+))?/"     \
  "(.+)?"
Kitware Robot's avatar
Kitware Robot committed
122
123
124
125
126
127
128
129
130
131

#ifdef _MSC_VER
#include <sys/utime.h>
#else
#include <utime.h>
#endif

// This is a hack to prevent warnings about these functions being
// declared but not referenced.
#if defined(__sgi) && !defined(__GNUC__)
Kitware Robot's avatar
Kitware Robot committed
132
133
#include <sys/termios.h>
namespace KWSYS_NAMESPACE {
Kitware Robot's avatar
Kitware Robot committed
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)),
Kitware Robot's avatar
Kitware Robot committed
143
144
    Ref5 = sizeof(cfsetospeed(0, 0)),
    Ref6 = sizeof(cfsetispeed(0, 0))
Kitware Robot's avatar
Kitware Robot committed
145
146
147
148
149
  };
};
}
#endif

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

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

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

Kitware Robot's avatar
Kitware Robot committed
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

Kitware Robot's avatar
Kitware Robot committed
215
#ifdef KWSYS_WINDOWS_DIRS
Kitware Robot's avatar
Kitware Robot committed
216
217
#include <wctype.h>

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

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

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

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

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

    resolved_path = "";
Kitware Robot's avatar
Kitware Robot committed
325
  } else {
Kitware Robot's avatar
Kitware Robot committed
326
327
    // if path resolution fails, return what was passed in
    resolved_path = path;
Kitware Robot's avatar
Kitware Robot committed
328
  }
Kitware Robot's avatar
Kitware Robot committed
329
330
331
332
333
}
#endif

#if !defined(_WIN32) && defined(__COMO__)
// Hack for como strict mode to avoid defining _SVID_SOURCE or _BSD_SOURCE.
Kitware Robot's avatar
Kitware Robot committed
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;
Kitware Robot's avatar
Kitware Robot committed
341
342
343
}
#endif

Kitware Robot's avatar
Kitware Robot committed
344
namespace KWSYS_NAMESPACE {
Kitware Robot's avatar
Kitware Robot committed
345
346
347
348
349
350

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

Kitware Robot's avatar
Kitware Robot committed
360
class SystemToolsTranslationMap : public std::map<std::string, std::string>
Kitware Robot's avatar
Kitware Robot committed
361
362
363
{
};

Kitware Robot's avatar
Kitware Robot committed
364
365
366
367
368
369
370
371
372
373
/* Type of character storing the environment.  */
#if defined(_WIN32)
typedef wchar_t envchar;
#else
typedef char envchar;
#endif

/* Order by environment key only (VAR from VAR=VALUE).  */
struct kwsysEnvCompare
{
Kitware Robot's avatar
Kitware Robot committed
374
375
  bool operator()(const envchar* l, const envchar* r) const
  {
Kitware Robot's avatar
Kitware Robot committed
376
377
378
#if defined(_WIN32)
    const wchar_t* leq = wcschr(l, L'=');
    const wchar_t* req = wcschr(r, L'=');
Kitware Robot's avatar
Kitware Robot committed
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;
    }
Kitware Robot's avatar
Kitware Robot committed
386
387
388
#else
    const char* leq = strchr(l, '=');
    const char* req = strchr(r, '=');
Kitware Robot's avatar
Kitware Robot committed
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;
Kitware Robot's avatar
Kitware Robot committed
395
    }
Kitware Robot's avatar
Kitware Robot committed
396
397
#endif
  }
Kitware Robot's avatar
Kitware Robot committed
398
399
};

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

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

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

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

Kitware Robot's avatar
Kitware Robot committed
442
443
444
445
class SystemToolsPathCaseMap
  : public std::map<std::string, std::string, SystemToolsPathCaseCmp>
{
};
Kitware Robot's avatar
Kitware Robot committed
446

Kitware Robot's avatar
Kitware Robot committed
447
448
449
class SystemToolsEnvMap : public std::map<std::string, std::string>
{
};
Kitware Robot's avatar
Kitware Robot committed
450
451
#endif

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

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

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

Kitware Robot's avatar
Kitware Robot committed
506
507
508
509
510
const char* SystemTools::GetEnv(const char* key)
{
  return SystemTools::GetEnvImpl(key);
}

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

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

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

Kitware Robot's avatar
Kitware Robot committed
540
541
542
543
544
545
546
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);
Kitware Robot's avatar
Kitware Robot committed
547
#endif
Kitware Robot's avatar
Kitware Robot committed
548
  return v != KWSYS_NULLPTR;
Kitware Robot's avatar
Kitware Robot committed
549
550
551
552
553
554
555
}

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

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

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

Kitware Robot's avatar
Kitware Robot committed
600
601
602
603
604
605
606
607
608
609
610
611
#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;

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

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

#if KWSYS_CXX_HAS_SETENV

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

Kitware Robot's avatar
Kitware Robot committed
661
bool SystemTools::UnPutEnv(const std::string& env)
Kitware Robot's avatar
Kitware Robot committed
662
663
664
665
666
667
668
669
670
671
672
673
674
{
  return kwsysUnPutEnv(env) == 0;
}

#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.  */

Kitware Robot's avatar
Kitware Robot committed
675
676
677
#ifdef __INTEL_COMPILER
#pragma warning disable 444 /* base has non-virtual destructor */
#endif
Kitware Robot's avatar
Kitware Robot committed
678

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

static kwsysEnv kwsysEnvInstance;

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

Kitware Robot's avatar
Kitware Robot committed
729
bool SystemTools::UnPutEnv(const std::string& env)
Kitware Robot's avatar
Kitware Robot committed
730
{
Kitware Robot's avatar
Kitware Robot committed
731
  return kwsysEnvInstance.UnPut(env.c_str());
Kitware Robot's avatar
Kitware Robot committed
732
733
734
735
736
737
738
739
740
741
742
743
744
}

#endif

const char* SystemTools::GetExecutableExtension()
{
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__VMS)
  return ".exe";
#else
  return "";
#endif
}

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

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

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

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

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

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

Kitware Robot's avatar
Kitware Robot committed
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.
Kitware Robot's avatar
Kitware Robot committed
807
808
809
void SystemTools::ReplaceString(std::string& source,
                                const std::string& replace,
                                const std::string& with)
Kitware Robot's avatar
Kitware Robot committed
810
811
{
  // do while hangs if replaceSize is 0
Kitware Robot's avatar
Kitware Robot committed
812
  if (replace.empty()) {
Kitware Robot's avatar
Kitware Robot committed
813
    return;
Kitware Robot's avatar
Kitware Robot committed
814
  }
Kitware Robot's avatar
Kitware Robot committed
815
816
817
818

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

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

Kitware Robot's avatar
Kitware Robot committed
827
828
  SystemTools::ReplaceString(source, replace, strlen(replace),
                             with ? with : "");
Kitware Robot's avatar
Kitware Robot committed
829
830
}

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

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

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

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

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

Kitware Robot's avatar
Kitware Robot committed
863
864
#if defined(_WIN32) && !defined(__CYGWIN__)

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

Kitware Robot's avatar
Kitware Robot committed
873
static bool SystemToolsParseRegistryKey(const std::string& key,
Kitware Robot's avatar
Kitware Robot committed
874
                                        HKEY& primaryKey, std::string& second,
Kitware Robot's avatar
Kitware Robot committed
875
                                        std::string& valuename)
Kitware Robot's avatar
Kitware Robot committed
876
{
Kitware Robot's avatar
Kitware Robot committed
877
  std::string primary = key;
Kitware Robot's avatar
Kitware Robot committed
878

Kitware Robot's avatar
Kitware Robot committed
879
  size_t start = primary.find('\\');
Kitware Robot's avatar
Kitware Robot committed
880
  if (start == std::string::npos) {
Kitware Robot's avatar
Kitware Robot committed
881
    return false;
Kitware Robot's avatar
Kitware Robot committed
882
  }
Kitware Robot's avatar
Kitware Robot committed
883

Kitware Robot's avatar
Kitware Robot committed
884
  size_t valuenamepos = primary.find(';');
Kitware Robot's avatar
Kitware Robot committed
885
886
887
  if (valuenamepos != std::string::npos) {
    valuename = primary.substr(valuenamepos + 1);
  }
Kitware Robot's avatar
Kitware Robot committed
888

Kitware Robot's avatar
Kitware Robot committed
889
  second = primary.substr(start + 1, valuenamepos - start - 1);
Kitware Robot's avatar
Kitware Robot committed
890
891
  primary = primary.substr(0, start);

Kitware Robot's avatar
Kitware Robot committed
892
  if (primary == "HKEY_CURRENT_USER") {
Kitware Robot's avatar
Kitware Robot committed
893
    primaryKey = HKEY_CURRENT_USER;
Kitware Robot's avatar
Kitware Robot committed
894
895
  }
  if (primary == "HKEY_CURRENT_CONFIG") {
Kitware Robot's avatar
Kitware Robot committed
896
    primaryKey = HKEY_CURRENT_CONFIG;
Kitware Robot's avatar
Kitware Robot committed
897
898
  }
  if (primary == "HKEY_CLASSES_ROOT") {
Kitware Robot's avatar
Kitware Robot committed
899
    primaryKey = HKEY_CLASSES_ROOT;
Kitware Robot's avatar
Kitware Robot committed
900
901
  }
  if (primary == "HKEY_LOCAL_MACHINE") {
Kitware Robot's avatar
Kitware Robot committed
902
    primaryKey = HKEY_LOCAL_MACHINE;
Kitware Robot's avatar
Kitware Robot committed
903
904
  }
  if (primary == "HKEY_USERS") {
Kitware Robot's avatar
Kitware Robot committed
905
    primaryKey = HKEY_USERS;
Kitware Robot's avatar
Kitware Robot committed
906
  }
Kitware Robot's avatar
Kitware Robot committed
907
908
909
910

  return true;
}

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

Kitware Robot's avatar
Kitware Robot committed
921
  if (view == SystemTools::KeyWOW64_32) {
Kitware Robot's avatar
Kitware Robot committed
922
    return mode | KWSYS_ST_KEY_WOW64_32KEY;
Kitware Robot's avatar
Kitware Robot committed
923
  } else if (view == SystemTools::KeyWOW64_64) {
Kitware Robot's avatar
Kitware Robot committed
924
    return mode | KWSYS_ST_KEY_WOW64_64KEY;
Kitware Robot's avatar
Kitware Robot committed
925
  }
Kitware Robot's avatar
Kitware Robot committed
926
927
928
929
  return mode;
}
#endif

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

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

    DWORD i = 0;
Kitware Robot's avatar
Kitware Robot committed
952
    while (RegEnumKeyW(hKey, i, name, dwNameSize) == ERROR_SUCCESS) {
Kitware Robot's avatar
Kitware Robot committed
953
      subkeys.push_back(Encoding::ToNarrow(name));
Kitware Robot's avatar
Kitware Robot committed
954
      ++i;
Kitware Robot's avatar
Kitware Robot committed
955
    }
Kitware Robot's avatar
Kitware Robot committed
956
957

    RegCloseKey(hKey);
Kitware Robot's avatar
Kitware Robot committed
958
  }
Kitware Robot's avatar
Kitware Robot committed
959
960
961
962

  return true;
}
#else
Kitware Robot's avatar
Kitware Robot committed
963
bool SystemTools::GetRegistrySubKeys(const std::string&,
Kitware Robot's avatar
Kitware Robot committed
964
                                     std::vector<std::string>&, KeyWOW64)
Kitware Robot's avatar
Kitware Robot committed
965
966
967
968
969
{
  return false;
}
#endif

Kitware Robot's avatar
Kitware Robot committed
970
971
972
973
974
975
976
977
// Read a registry value.
// Example :
//      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__)
Kitware Robot's avatar
Kitware Robot committed
978
bool SystemTools::ReadRegistryValue(const std::string& key, std::string& value,