SystemTools.cxx 132 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
23
#include KWSYS_HEADER(FStream.hxx)
#include KWSYS_HEADER(Encoding.hxx)
Kitware Robot's avatar
Kitware Robot committed
24

Kitware Robot's avatar
Kitware Robot committed
25
#include <algorithm>
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
111
#if defined(_WIN32) || defined(__LIBCATAMOUNT__)
#undef HAVE_GETPWNAM
#undef HAVE_TTY_INFO
Kitware Robot's avatar
Kitware Robot committed
112
#else
Kitware Robot's avatar
Kitware Robot committed
113
114
#define HAVE_GETPWNAM 1
#define HAVE_TTY_INFO 1
Kitware Robot's avatar
Kitware Robot committed
115
116
117
#endif

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

#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
131
132
#include <sys/termios.h>
namespace KWSYS_NAMESPACE {
Kitware Robot's avatar
Kitware Robot committed
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)),
Kitware Robot's avatar
Kitware Robot committed
142
143
    Ref5 = sizeof(cfsetospeed(0, 0)),
    Ref6 = sizeof(cfsetispeed(0, 0))
Kitware Robot's avatar
Kitware Robot committed
144
145
146
147
148
  };
};
}
#endif

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

/* The maximum length of a file name.  */
#if defined(PATH_MAX)
Kitware Robot's avatar
Kitware Robot committed
158
#define KWSYS_SYSTEMTOOLS_MAXPATH PATH_MAX
Kitware Robot's avatar
Kitware Robot committed
159
#elif defined(MAXPATHLEN)
Kitware Robot's avatar
Kitware Robot committed
160
#define KWSYS_SYSTEMTOOLS_MAXPATH MAXPATHLEN
Kitware Robot's avatar
Kitware Robot committed
161
#else
Kitware Robot's avatar
Kitware Robot committed
162
#define KWSYS_SYSTEMTOOLS_MAXPATH 16384
Kitware Robot's avatar
Kitware Robot committed
163
164
165
166
167
168
169
170
171
#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
172
#if defined(__BEOS__) && !defined(__ZETA__)
Kitware Robot's avatar
Kitware Robot committed
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.
Kitware Robot's avatar
Kitware Robot committed
183
static inline char* realpath(const char* path, char* resolved_path)
Kitware Robot's avatar
Kitware Robot committed
184
185
186
187
{
  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
188
189
190
191
  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
192
193
      return resolved_path;
    }
Kitware Robot's avatar
Kitware Robot committed
194
195
  }
  return NULL; // something went wrong.
Kitware Robot's avatar
Kitware Robot committed
196
197
198
}
#endif

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

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

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

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

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

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

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

    resolved_path = "";
Kitware Robot's avatar
Kitware Robot committed
320
  } else {
Kitware Robot's avatar
Kitware Robot committed
321
322
    // if path resolution fails, return what was passed in
    resolved_path = path;
Kitware Robot's avatar
Kitware Robot committed
323
  }
Kitware Robot's avatar
Kitware Robot committed
324
325
326
327
328
}
#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
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;
Kitware Robot's avatar
Kitware Robot committed
336
337
338
}
#endif

Kitware Robot's avatar
Kitware Robot committed
339
namespace KWSYS_NAMESPACE {
Kitware Robot's avatar
Kitware Robot committed
340
341
342
343
344
345

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

Kitware Robot's avatar
Kitware Robot committed
355
class SystemToolsTranslationMap : public std::map<std::string, std::string>
Kitware Robot's avatar
Kitware Robot committed
356
357
358
{
};

Kitware Robot's avatar
Kitware Robot committed
359
360
361
362
363
364
365
366
367
368
/* 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
369
370
  bool operator()(const envchar* l, const envchar* r) const
  {
Kitware Robot's avatar
Kitware Robot committed
371
372
373
#if defined(_WIN32)
    const wchar_t* leq = wcschr(l, L'=');
    const wchar_t* req = wcschr(r, L'=');
Kitware Robot's avatar
Kitware Robot committed
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;
    }
Kitware Robot's avatar
Kitware Robot committed
381
382
383
#else
    const char* leq = strchr(l, '=');
    const char* req = strchr(r, '=');
Kitware Robot's avatar
Kitware Robot committed
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;
Kitware Robot's avatar
Kitware Robot committed
390
    }
Kitware Robot's avatar
Kitware Robot committed
391
392
#endif
  }
Kitware Robot's avatar
Kitware Robot committed
393
394
};

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

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

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

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

Kitware Robot's avatar
Kitware Robot committed
437
438
439
440
class SystemToolsPathCaseMap
  : public std::map<std::string, std::string, SystemToolsPathCaseCmp>
{
};
Kitware Robot's avatar
Kitware Robot committed
441

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

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

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

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

Kitware Robot's avatar
Kitware Robot committed
501
502
503
504
505
const char* SystemTools::GetEnv(const char* key)
{
  return SystemTools::GetEnvImpl(key);
}

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

Kitware Robot's avatar
Kitware Robot committed
511
bool SystemTools::GetEnv(const char* key, std::string& result)
Kitware Robot's avatar
Kitware Robot committed
512
{
Kitware Robot's avatar
Kitware Robot committed
513
514
515
#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
516
  if (wv) {
Kitware Robot's avatar
Kitware Robot committed
517
518
    result = Encoding::ToNarrow(wv);
    return true;
Kitware Robot's avatar
Kitware Robot committed
519
  }
Kitware Robot's avatar
Kitware Robot committed
520
#else
Kitware Robot's avatar
Kitware Robot committed
521
  const char* v = getenv(key);
Kitware Robot's avatar
Kitware Robot committed
522
  if (v) {
Kitware Robot's avatar
Kitware Robot committed
523
524
    result = v;
    return true;
Kitware Robot's avatar
Kitware Robot committed
525
  }
Kitware Robot's avatar
Kitware Robot committed
526
527
#endif
  return false;
Kitware Robot's avatar
Kitware Robot committed
528
529
}

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

Kitware Robot's avatar
Kitware Robot committed
535
536
537
538
539
540
541
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
542
#endif
Kitware Robot's avatar
Kitware Robot committed
543
544
545
546
547
548
549
550
  return v != 0;
}

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

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

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

Kitware Robot's avatar
Kitware Robot committed
595
596
597
598
599
600
601
602
603
604
605
606
607
#elif defined(_WIN32)
/* putenv("A=") places "A=" in the environment, which is as close to
   removal as we can get with the putenv API.  We have to leak the
   most recent value placed in the environment for each variable name
   on program exit in case exit routines access it.  */

static kwsysEnvSet kwsysUnPutEnvSet;

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

Kitware Robot's avatar
Kitware Robot committed
618
619
#else
/* Manipulate the "environ" global directly.  */
Kitware Robot's avatar
Kitware Robot committed
620
static int kwsysUnPutEnv(const std::string& env)
Kitware Robot's avatar
Kitware Robot committed
621
{
Kitware Robot's avatar
Kitware Robot committed
622
623
  size_t pos = env.find('=');
  size_t const len = pos == env.npos ? env.size() : pos;
Kitware Robot's avatar
Kitware Robot committed
624
625
  int in = 0;
  int out = 0;
Kitware Robot's avatar
Kitware Robot committed
626
627
628
  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
629
      ++in;
Kitware Robot's avatar
Kitware Robot committed
630
    } else {
Kitware Robot's avatar
Kitware Robot committed
631
632
      environ[out++] = environ[in++];
    }
Kitware Robot's avatar
Kitware Robot committed
633
634
  }
  while (out < in) {
Kitware Robot's avatar
Kitware Robot committed
635
    environ[out++] = 0;
Kitware Robot's avatar
Kitware Robot committed
636
  }
Kitware Robot's avatar
Kitware Robot committed
637
638
639
640
641
642
643
644
  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
645
bool SystemTools::PutEnv(const std::string& env)
Kitware Robot's avatar
Kitware Robot committed
646
{
Kitware Robot's avatar
Kitware Robot committed
647
  size_t pos = env.find('=');
Kitware Robot's avatar
Kitware Robot committed
648
  if (pos != env.npos) {
Kitware Robot's avatar
Kitware Robot committed
649
650
    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
651
  } else {
Kitware Robot's avatar
Kitware Robot committed
652
    return kwsysUnPutEnv(env) == 0;
Kitware Robot's avatar
Kitware Robot committed
653
  }
Kitware Robot's avatar
Kitware Robot committed
654
655
}

Kitware Robot's avatar
Kitware Robot committed
656
bool SystemTools::UnPutEnv(const std::string& env)
Kitware Robot's avatar
Kitware Robot committed
657
658
659
660
661
662
663
664
665
666
667
668
669
{
  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
670
671
672
#ifdef __INTEL_COMPILER
#pragma warning disable 444 /* base has non-virtual destructor */
#endif
Kitware Robot's avatar
Kitware Robot committed
673

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

static kwsysEnv kwsysEnvInstance;

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

Kitware Robot's avatar
Kitware Robot committed
724
bool SystemTools::UnPutEnv(const std::string& env)
Kitware Robot's avatar
Kitware Robot committed
725
{
Kitware Robot's avatar
Kitware Robot committed
726
  return kwsysEnvInstance.UnPut(env.c_str());
Kitware Robot's avatar
Kitware Robot committed
727
728
729
730
731
732
733
734
735
736
737
738
739
}

#endif

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

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

bool SystemTools::MakeDirectory(const char* path)
{
Kitware Robot's avatar
Kitware Robot committed
752
  if (!path) {
Kitware Robot's avatar
Kitware Robot committed
753
    return false;
Kitware Robot's avatar
Kitware Robot committed
754
  }
Kitware Robot's avatar
Kitware Robot committed
755
  return SystemTools::MakeDirectory(std::string(path));
Kitware Robot's avatar
Kitware Robot committed
756
757
}

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

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

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

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

Kitware Robot's avatar
Kitware Robot committed
815
816
  SystemTools::ReplaceString(source, replace, strlen(replace),
                             with ? with : "");
Kitware Robot's avatar
Kitware Robot committed
817
818
}

Kitware Robot's avatar
Kitware Robot committed
819
820
void SystemTools::ReplaceString(std::string& source, const char* replace,
                                size_t replaceSize, const std::string& with)
Kitware Robot's avatar
Kitware Robot committed
821
{
Kitware Robot's avatar
Kitware Robot committed
822
823
  const char* src = source.c_str();
  char* searchPos = const_cast<char*>(strstr(src, replace));
Kitware Robot's avatar
Kitware Robot committed
824
825

  // get out quick if string is not found
Kitware Robot's avatar
Kitware Robot committed
826
  if (!searchPos) {
Kitware Robot's avatar
Kitware Robot committed
827
    return;
Kitware Robot's avatar
Kitware Robot committed
828
  }
Kitware Robot's avatar
Kitware Robot committed
829
830

  // perform replacements until done
Kitware Robot's avatar
Kitware Robot committed
831
832
  char* orig = strdup(src);
  char* currentPos = orig;
Kitware Robot's avatar
Kitware Robot committed
833
834
835
  searchPos = searchPos - src + orig;

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

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

#if defined(KEY_WOW64_32KEY) && defined(KEY_WOW64_64KEY)
Kitware Robot's avatar
Kitware Robot committed
852
853
#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
854
#else
Kitware Robot's avatar
Kitware Robot committed
855
856
#define KWSYS_ST_KEY_WOW64_32KEY 0x0200
#define KWSYS_ST_KEY_WOW64_64KEY 0x0100
Kitware Robot's avatar
Kitware Robot committed
857
858
859
#endif

#if defined(_WIN32) && !defined(__CYGWIN__)
Kitware Robot's avatar
Kitware Robot committed
860
static bool SystemToolsParseRegistryKey(const std::string& key,
Kitware Robot's avatar
Kitware Robot committed
861
                                        HKEY& primaryKey, std::string& second,
Kitware Robot's avatar
Kitware Robot committed
862
                                        std::string& valuename)
Kitware Robot's avatar
Kitware Robot committed
863
{
Kitware Robot's avatar
Kitware Robot committed
864
  std::string primary = key;
Kitware Robot's avatar
Kitware Robot committed
865

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

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

Kitware Robot's avatar
Kitware Robot committed
876
  second = primary.substr(start + 1, valuenamepos - start - 1);
Kitware Robot's avatar
Kitware Robot committed
877
878
  primary = primary.substr(0, start);

Kitware Robot's avatar
Kitware Robot committed
879
  if (primary == "HKEY_CURRENT_USER") {
Kitware Robot's avatar
Kitware Robot committed
880
    primaryKey = HKEY_CURRENT_USER;
Kitware Robot's avatar
Kitware Robot committed
881
882
  }
  if (primary == "HKEY_CURRENT_CONFIG") {
Kitware Robot's avatar
Kitware Robot committed
883
    primaryKey = HKEY_CURRENT_CONFIG;
Kitware Robot's avatar
Kitware Robot committed
884
885
  }
  if (primary == "HKEY_CLASSES_ROOT") {
Kitware Robot's avatar
Kitware Robot committed
886
    primaryKey = HKEY_CLASSES_ROOT;
Kitware Robot's avatar
Kitware Robot committed
887
888
  }
  if (primary == "HKEY_LOCAL_MACHINE") {
Kitware Robot's avatar
Kitware Robot committed
889
    primaryKey = HKEY_LOCAL_MACHINE;
Kitware Robot's avatar
Kitware Robot committed
890
891
  }
  if (primary == "HKEY_USERS") {
Kitware Robot's avatar
Kitware Robot committed
892
    primaryKey = HKEY_USERS;
Kitware Robot's avatar
Kitware Robot committed
893
  }
Kitware Robot's avatar
Kitware Robot committed
894
895
896
897

  return true;
}

Kitware Robot's avatar
Kitware Robot committed
898
899
900
901
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
902
903
904
  static FARPROC wow64p =
    GetProcAddress(GetModuleHandleW(L"kernel32"), "IsWow64Process");
  if (wow64p == NULL) {
Kitware Robot's avatar
Kitware Robot committed
905
    return mode;
Kitware Robot's avatar
Kitware Robot committed
906
  }
Kitware Robot's avatar
Kitware Robot committed
907

Kitware Robot's avatar
Kitware Robot committed
908
  if (view == SystemTools::KeyWOW64_32) {
Kitware Robot's avatar
Kitware Robot committed
909
    return mode | KWSYS_ST_KEY_WOW64_32KEY;
Kitware Robot's avatar
Kitware Robot committed
910
  } else if (view == SystemTools::KeyWOW64_64) {
Kitware Robot's avatar
Kitware Robot committed
911
    return mode | KWSYS_ST_KEY_WOW64_64KEY;
Kitware Robot's avatar
Kitware Robot committed
912
  }
Kitware Robot's avatar
Kitware Robot committed
913
914
915
916
  return mode;
}
#endif

Kitware Robot's avatar
Kitware Robot committed
917
#if defined(_WIN32) && !defined(__CYGWIN__)
Kitware Robot's avatar
Kitware Robot committed
918
919
920
bool SystemTools::GetRegistrySubKeys(const std::string& key,
                                     std::vector<std::string>& subkeys,
                                     KeyWOW64 view)
Kitware Robot's avatar
Kitware Robot committed
921
922
{
  HKEY primaryKey = HKEY_CURRENT_USER;
Kitware Robot's avatar
Kitware Robot committed
923
924
  std::string second;
  std::string valuename;
Kitware Robot's avatar
Kitware Robot committed
925
  if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) {
Kitware Robot's avatar
Kitware Robot committed
926
    return false;
Kitware Robot's avatar
Kitware Robot committed
927
  }
Kitware Robot's avatar
Kitware Robot committed
928
929

  HKEY hKey;
Kitware Robot's avatar
Kitware Robot committed
930
931
932
  if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0,
                    SystemToolsMakeRegistryMode(KEY_READ, view),
                    &hKey) != ERROR_SUCCESS) {
Kitware Robot's avatar
Kitware Robot committed
933
    return false;
Kitware Robot's avatar
Kitware Robot committed
934
  } else {
Kitware Robot's avatar
Kitware Robot committed
935
    wchar_t name[1024];
Kitware Robot's avatar
Kitware Robot committed
936
    DWORD dwNameSize = sizeof(name) / sizeof(name[0]);
Kitware Robot's avatar
Kitware Robot committed
937
938

    DWORD i = 0;
Kitware Robot's avatar
Kitware Robot committed
939
    while (RegEnumKeyW(hKey, i, name, dwNameSize) == ERROR_SUCCESS) {
Kitware Robot's avatar
Kitware Robot committed
940
      subkeys.push_back(Encoding::ToNarrow(name));
Kitware Robot's avatar
Kitware Robot committed
941
      ++i;
Kitware Robot's avatar
Kitware Robot committed
942
    }
Kitware Robot's avatar
Kitware Robot committed
943
944

    RegCloseKey(hKey);
Kitware Robot's avatar
Kitware Robot committed
945
  }
Kitware Robot's avatar
Kitware Robot committed
946
947
948
949

  return true;
}
#else
Kitware Robot's avatar
Kitware Robot committed
950
bool SystemTools::GetRegistrySubKeys(const std::string&,
Kitware Robot's avatar
Kitware Robot committed
951
                                     std::vector<std::string>&, KeyWOW64)
Kitware Robot's avatar
Kitware Robot committed
952
953
954
955
956
{
  return false;
}
#endif

Kitware Robot's avatar
Kitware Robot committed
957
958
959
960
961
962
963
964
// 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
965
bool SystemTools::ReadRegistryValue(const std::string& key, std::string& value,
Kitware Robot's avatar
Kitware Robot committed
966
967
968
                                    KeyWOW64 view)
{
  bool valueset = false;
Kitware Robot's avatar
Kitware Robot committed
969
  HKEY primaryKey = HKEY_CURRENT_USER;
Kitware Robot's avatar
Kitware Robot committed
970
971
  std::string second;
  std::string valuename;
Kitware Robot's avatar
Kitware Robot committed
972
  if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) {