resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmSystemTools.cxx
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3
4 #if !defined(_WIN32) && !defined(__sun) && !defined(__OpenBSD__)
5 // POSIX APIs are needed
6 // NOLINTNEXTLINE(bugprone-reserved-identifier)
7 #  define _POSIX_C_SOURCE 200809L
8 #endif
9 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__QNX__)
10 // For isascii
11 // NOLINTNEXTLINE(bugprone-reserved-identifier)
12 #  define _XOPEN_SOURCE 700
13 #endif
14 #if defined(__APPLE__)
15 // Restore Darwin APIs removed by _POSIX_C_SOURCE.
16 // NOLINTNEXTLINE(bugprone-reserved-identifier)
17 #  define _DARWIN_C_SOURCE
18 #endif
19
20 #include "cmSystemTools.h"
21
22 #include <cm/optional>
23 #include <cmext/algorithm>
24 #include <cmext/string_view>
25
26 #include <cm3p/uv.h>
27
28 #include "cmDuration.h"
29 #include "cmELF.h"
30 #include "cmMessageMetadata.h"
31 #include "cmProcessOutput.h"
32 #include "cmRange.h"
33 #include "cmStringAlgorithms.h"
34 #include "cmValue.h"
35
36 #if !defined(CMAKE_BOOTSTRAP)
37 #  include <cm3p/archive.h>
38 #  include <cm3p/archive_entry.h>
39
40 #  include "cmArchiveWrite.h"
41 #  include "cmLocale.h"
42 #  ifndef __LA_INT64_T
43 #    define __LA_INT64_T la_int64_t
44 #  endif
45 #  ifndef __LA_SSIZE_T
46 #    define __LA_SSIZE_T la_ssize_t
47 #  endif
48 #endif
49
50 #if !defined(CMAKE_BOOTSTRAP)
51 #  if defined(_WIN32)
52 #    include <cm/memory>
53 #  endif
54 #  include "cmCryptoHash.h"
55 #endif
56
57 #if defined(CMake_USE_MACH_PARSER)
58 #  include "cmMachO.h"
59 #endif
60
61 #if defined(CMake_USE_XCOFF_PARSER)
62 #  include "cmXCOFF.h"
63 #endif
64
65 #include <algorithm>
66 #include <cassert>
67 #include <cctype>
68 #include <cerrno>
69 #include <cstdio>
70 #include <cstdlib>
71 #include <cstring>
72 #include <ctime>
73 #include <functional>
74 #include <iostream>
75 #include <sstream>
76 #include <utility>
77 #include <vector>
78
79 #include <fcntl.h>
80
81 #include "cmsys/Directory.hxx"
82 #include "cmsys/Encoding.hxx"
83 #include "cmsys/FStream.hxx"
84 #include "cmsys/RegularExpression.hxx"
85 #include "cmsys/System.h"
86 #include "cmsys/Terminal.h"
87
88 #if defined(_WIN32)
89 #  include <windows.h>
90 // include wincrypt.h after windows.h
91 #  include <wincrypt.h>
92 #else
93 #  include <unistd.h>
94
95 #  include <sys/time.h>
96 #endif
97
98 #if defined(_WIN32) &&                                                        \
99   (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__MINGW32__))
100 #  include <io.h>
101 #endif
102
103 #if defined(__APPLE__)
104 #  include <mach-o/dyld.h>
105 #endif
106
107 #ifdef __QNX__
108 #  include <malloc.h> /* for malloc/free on QNX */
109 #endif
110
111 #if !defined(_WIN32) && !defined(__ANDROID__)
112 #  include <sys/utsname.h>
113 #endif
114
115 #if defined(_MSC_VER) && _MSC_VER >= 1800
116 #  define CM_WINDOWS_DEPRECATED_GetVersionEx
117 #endif
118
119 namespace {
120
121 cmSystemTools::InterruptCallback s_InterruptCallback;
122 cmSystemTools::MessageCallback s_MessageCallback;
123 cmSystemTools::OutputCallback s_StderrCallback;
124 cmSystemTools::OutputCallback s_StdoutCallback;
125
126 } // namespace
127
128 #if !defined(HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE)
129 // For GetEnvironmentVariables
130 #  if defined(_WIN32)
131 extern __declspec(dllimport) char** environ;
132 #  else
133 extern char** environ;
134 #  endif
135 #endif
136
137 #if !defined(CMAKE_BOOTSTRAP)
138 static std::string cm_archive_entry_pathname(struct archive_entry* entry)
139 {
140 #  if cmsys_STL_HAS_WSTRING
141   return cmsys::Encoding::ToNarrow(archive_entry_pathname_w(entry));
142 #  else
143   return archive_entry_pathname(entry);
144 #  endif
145 }
146
147 static int cm_archive_read_open_file(struct archive* a, const char* file,
148                                      int block_size)
149 {
150 #  if cmsys_STL_HAS_WSTRING
151   std::wstring wfile = cmsys::Encoding::ToWide(file);
152   return archive_read_open_filename_w(a, wfile.c_str(), block_size);
153 #  else
154   return archive_read_open_filename(a, file, block_size);
155 #  endif
156 }
157 #endif
158
159 #ifdef _WIN32
160 #elif defined(__APPLE__)
161 #  include <crt_externs.h>
162
163 #  define environ (*_NSGetEnviron())
164 #endif
165
166 bool cmSystemTools::s_RunCommandHideConsole = false;
167 bool cmSystemTools::s_DisableRunCommandOutput = false;
168 bool cmSystemTools::s_ErrorOccurred = false;
169 bool cmSystemTools::s_FatalErrorOccurred = false;
170 bool cmSystemTools::s_ForceUnixPaths = false;
171
172 // replace replace with with as many times as it shows up in source.
173 // write the result into source.
174 #if defined(_WIN32) && !defined(__CYGWIN__)
175 void cmSystemTools::ExpandRegistryValues(std::string& source, KeyWOW64 view)
176 {
177   // Regular expression to match anything inside [...] that begins in HKEY.
178   // Note that there is a special rule for regular expressions to match a
179   // close square-bracket inside a list delimited by square brackets.
180   // The "[^]]" part of this expression will match any character except
181   // a close square-bracket.  The ']' character must be the first in the
182   // list of characters inside the [^...] block of the expression.
183   cmsys::RegularExpression regEntry("\\[(HKEY[^]]*)\\]");
184
185   // check for black line or comment
186   while (regEntry.find(source)) {
187     // the arguments are the second match
188     std::string key = regEntry.match(1);
189     std::string val;
190     if (ReadRegistryValue(key.c_str(), val, view)) {
191       std::string reg = cmStrCat('[', key, ']');
192       cmSystemTools::ReplaceString(source, reg.c_str(), val.c_str());
193     } else {
194       std::string reg = cmStrCat('[', key, ']');
195       cmSystemTools::ReplaceString(source, reg.c_str(), "/registry");
196     }
197   }
198 }
199 #else
200 void cmSystemTools::ExpandRegistryValues(std::string& source,
201                                          KeyWOW64 /*unused*/)
202 {
203   cmsys::RegularExpression regEntry("\\[(HKEY[^]]*)\\]");
204   while (regEntry.find(source)) {
205     // the arguments are the second match
206     std::string key = regEntry.match(1);
207     std::string reg = cmStrCat('[', key, ']');
208     cmSystemTools::ReplaceString(source, reg.c_str(), "/registry");
209   }
210 }
211 #endif
212
213 std::string cmSystemTools::HelpFileName(cm::string_view str)
214 {
215   std::string name(str);
216   cmSystemTools::ReplaceString(name, "<", "");
217   cmSystemTools::ReplaceString(name, ">", "");
218   return name;
219 }
220
221 void cmSystemTools::Error(const std::string& m)
222 {
223   std::string message = "CMake Error: " + m;
224   cmSystemTools::s_ErrorOccurred = true;
225   cmSystemTools::Message(message, "Error");
226 }
227
228 void cmSystemTools::SetInterruptCallback(InterruptCallback f)
229 {
230   s_InterruptCallback = std::move(f);
231 }
232
233 bool cmSystemTools::GetInterruptFlag()
234 {
235   if (s_InterruptCallback) {
236     return s_InterruptCallback();
237   }
238   return false;
239 }
240
241 void cmSystemTools::SetMessageCallback(MessageCallback f)
242 {
243   s_MessageCallback = std::move(f);
244 }
245
246 void cmSystemTools::SetStdoutCallback(OutputCallback f)
247 {
248   s_StdoutCallback = std::move(f);
249 }
250
251 void cmSystemTools::SetStderrCallback(OutputCallback f)
252 {
253   s_StderrCallback = std::move(f);
254 }
255
256 void cmSystemTools::Stderr(const std::string& s)
257 {
258   if (s_StderrCallback) {
259     s_StderrCallback(s);
260   } else {
261     std::cerr << s << std::flush;
262   }
263 }
264
265 void cmSystemTools::Stdout(const std::string& s)
266 {
267   if (s_StdoutCallback) {
268     s_StdoutCallback(s);
269   } else {
270     std::cout << s << std::flush;
271   }
272 }
273
274 void cmSystemTools::Message(const std::string& m, const char* title)
275 {
276   cmMessageMetadata md;
277   md.title = title;
278   Message(m, md);
279 }
280
281 void cmSystemTools::Message(const std::string& m, const cmMessageMetadata& md)
282 {
283   if (s_MessageCallback) {
284     s_MessageCallback(m, md);
285   } else {
286     std::cerr << m << std::endl;
287   }
288 }
289
290 void cmSystemTools::ReportLastSystemError(const char* msg)
291 {
292   std::string m =
293     cmStrCat(msg, ": System Error: ", Superclass::GetLastSystemError());
294   cmSystemTools::Error(m);
295 }
296
297 void cmSystemTools::ParseWindowsCommandLine(const char* command,
298                                             std::vector<std::string>& args)
299 {
300   // See the MSDN document "Parsing C Command-Line Arguments" at
301   // http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx for rules
302   // of parsing the windows command line.
303
304   bool in_argument = false;
305   bool in_quotes = false;
306   int backslashes = 0;
307   std::string arg;
308   for (const char* c = command; *c; ++c) {
309     if (*c == '\\') {
310       ++backslashes;
311       in_argument = true;
312     } else if (*c == '"') {
313       int backslash_pairs = backslashes >> 1;
314       int backslash_escaped = backslashes & 1;
315       arg.append(backslash_pairs, '\\');
316       backslashes = 0;
317       if (backslash_escaped) {
318         /* An odd number of backslashes precede this quote.
319            It is escaped.  */
320         arg.append(1, '"');
321       } else {
322         /* An even number of backslashes precede this quote.
323            It is not escaped.  */
324         in_quotes = !in_quotes;
325       }
326       in_argument = true;
327     } else {
328       arg.append(backslashes, '\\');
329       backslashes = 0;
330       if (cmIsSpace(*c)) {
331         if (in_quotes) {
332           arg.append(1, *c);
333         } else if (in_argument) {
334           args.push_back(arg);
335           arg.clear();
336           in_argument = false;
337         }
338       } else {
339         in_argument = true;
340         arg.append(1, *c);
341       }
342     }
343   }
344   arg.append(backslashes, '\\');
345   if (in_argument) {
346     args.push_back(arg);
347   }
348 }
349
350 class cmSystemToolsArgV
351 {
352   char** ArgV;
353
354 public:
355   cmSystemToolsArgV(char** argv)
356     : ArgV(argv)
357   {
358   }
359   ~cmSystemToolsArgV()
360   {
361     for (char** arg = this->ArgV; arg && *arg; ++arg) {
362       free(*arg);
363     }
364     free(this->ArgV);
365   }
366   cmSystemToolsArgV(const cmSystemToolsArgV&) = delete;
367   cmSystemToolsArgV& operator=(const cmSystemToolsArgV&) = delete;
368   void Store(std::vector<std::string>& args) const
369   {
370     for (char** arg = this->ArgV; arg && *arg; ++arg) {
371       args.emplace_back(*arg);
372     }
373   }
374 };
375
376 void cmSystemTools::ParseUnixCommandLine(const char* command,
377                                          std::vector<std::string>& args)
378 {
379   // Invoke the underlying parser.
380   cmSystemToolsArgV argv(cmsysSystem_Parse_CommandForUnix(command, 0));
381   argv.Store(args);
382 }
383
384 std::vector<std::string> cmSystemTools::HandleResponseFile(
385   std::vector<std::string>::const_iterator argBeg,
386   std::vector<std::string>::const_iterator argEnd)
387 {
388   std::vector<std::string> arg_full;
389   for (std::string const& arg : cmMakeRange(argBeg, argEnd)) {
390     if (cmHasLiteralPrefix(arg, "@")) {
391       cmsys::ifstream responseFile(arg.substr(1).c_str(), std::ios::in);
392       if (!responseFile) {
393         std::string error = cmStrCat("failed to open for reading (",
394                                      cmSystemTools::GetLastSystemError(),
395                                      "):\n  ", cm::string_view(arg).substr(1));
396         cmSystemTools::Error(error);
397       } else {
398         std::string line;
399         cmSystemTools::GetLineFromStream(responseFile, line);
400         std::vector<std::string> args2;
401 #ifdef _WIN32
402         cmSystemTools::ParseWindowsCommandLine(line.c_str(), args2);
403 #else
404         cmSystemTools::ParseUnixCommandLine(line.c_str(), args2);
405 #endif
406         cm::append(arg_full, args2);
407       }
408     } else {
409       arg_full.push_back(arg);
410     }
411   }
412   return arg_full;
413 }
414
415 std::vector<std::string> cmSystemTools::ParseArguments(const std::string& cmd)
416 {
417   std::vector<std::string> args;
418   std::string arg;
419
420   bool win_path = false;
421
422   const char* command = cmd.c_str();
423   if (command[0] && command[1] &&
424       ((command[0] != '/' && command[1] == ':' && command[2] == '\\') ||
425        (command[0] == '\"' && command[1] != '/' && command[2] == ':' &&
426         command[3] == '\\') ||
427        (command[0] == '\'' && command[1] != '/' && command[2] == ':' &&
428         command[3] == '\\') ||
429        (command[0] == '\\' && command[1] == '\\'))) {
430     win_path = true;
431   }
432   // Split the command into an argv array.
433   for (const char* c = command; *c;) {
434     // Skip over whitespace.
435     while (*c == ' ' || *c == '\t') {
436       ++c;
437     }
438     arg.clear();
439     if (*c == '"') {
440       // Parse a quoted argument.
441       ++c;
442       while (*c && *c != '"') {
443         arg.append(1, *c);
444         ++c;
445       }
446       if (*c) {
447         ++c;
448       }
449       args.push_back(arg);
450     } else if (*c == '\'') {
451       // Parse a quoted argument.
452       ++c;
453       while (*c && *c != '\'') {
454         arg.append(1, *c);
455         ++c;
456       }
457       if (*c) {
458         ++c;
459       }
460       args.push_back(arg);
461     } else if (*c) {
462       // Parse an unquoted argument.
463       while (*c && *c != ' ' && *c != '\t') {
464         if (*c == '\\' && !win_path) {
465           ++c;
466           if (*c) {
467             arg.append(1, *c);
468             ++c;
469           }
470         } else {
471           arg.append(1, *c);
472           ++c;
473         }
474       }
475       args.push_back(arg);
476     }
477   }
478
479   return args;
480 }
481
482 bool cmSystemTools::SplitProgramFromArgs(std::string const& command,
483                                          std::string& program,
484                                          std::string& args)
485 {
486   const char* c = command.c_str();
487
488   // Skip leading whitespace.
489   while (isspace(static_cast<unsigned char>(*c))) {
490     ++c;
491   }
492
493   // Parse one command-line element up to an unquoted space.
494   bool in_escape = false;
495   bool in_double = false;
496   bool in_single = false;
497   for (; *c; ++c) {
498     if (in_single) {
499       if (*c == '\'') {
500         in_single = false;
501       } else {
502         program += *c;
503       }
504     } else if (in_escape) {
505       in_escape = false;
506       program += *c;
507     } else if (*c == '\\') {
508       in_escape = true;
509     } else if (in_double) {
510       if (*c == '"') {
511         in_double = false;
512       } else {
513         program += *c;
514       }
515     } else if (*c == '"') {
516       in_double = true;
517     } else if (*c == '\'') {
518       in_single = true;
519     } else if (isspace(static_cast<unsigned char>(*c))) {
520       break;
521     } else {
522       program += *c;
523     }
524   }
525
526   // The remainder of the command line holds unparsed arguments.
527   args = c;
528
529   return !in_single && !in_escape && !in_double;
530 }
531
532 size_t cmSystemTools::CalculateCommandLineLengthLimit()
533 {
534   size_t sz =
535 #ifdef _WIN32
536     // There's a maximum of 65536 bytes and thus 32768 WCHARs on Windows
537     // However, cmd.exe itself can only handle 8191 WCHARs and Ninja for
538     // example uses it to spawn processes.
539     size_t(8191);
540 #elif defined(__linux)
541     // MAX_ARG_STRLEN is the maximum length of a string permissible for
542     // the execve() syscall on Linux. It's defined as (PAGE_SIZE * 32)
543     // in Linux's binfmts.h
544     static_cast<size_t>(sysconf(_SC_PAGESIZE) * 32);
545 #else
546     size_t(0);
547 #endif
548
549 #if defined(_SC_ARG_MAX)
550   // ARG_MAX is the maximum size of the command and environment
551   // that can be passed to the exec functions on UNIX.
552   // The value in climits does not need to be present and may
553   // depend upon runtime memory constraints, hence sysconf()
554   // should be used to query it.
555   long szArgMax = sysconf(_SC_ARG_MAX);
556   // A return value of -1 signifies an undetermined limit, but
557   // it does not imply an infinite limit, and thus is ignored.
558   if (szArgMax != -1) {
559     // We estimate the size of the environment block to be 1000.
560     // This isn't accurate at all, but leaves some headroom.
561     szArgMax = szArgMax < 1000 ? 0 : szArgMax - 1000;
562 #  if defined(_WIN32) || defined(__linux)
563     sz = std::min(sz, static_cast<size_t>(szArgMax));
564 #  else
565     sz = static_cast<size_t>(szArgMax);
566 #  endif
567   }
568 #endif
569   return sz;
570 }
571
572 bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
573                                      std::string* captureStdOut,
574                                      std::string* captureStdErr, int* retVal,
575                                      const char* dir, OutputOption outputflag,
576                                      cmDuration timeout, Encoding encoding)
577 {
578   std::vector<const char*> argv;
579   argv.reserve(command.size() + 1);
580   for (std::string const& cmd : command) {
581     argv.push_back(cmd.c_str());
582   }
583   argv.push_back(nullptr);
584
585   cmsysProcess* cp = cmsysProcess_New();
586   cmsysProcess_SetCommand(cp, argv.data());
587   cmsysProcess_SetWorkingDirectory(cp, dir);
588   if (cmSystemTools::GetRunCommandHideConsole()) {
589     cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
590   }
591
592   if (outputflag == OUTPUT_PASSTHROUGH) {
593     cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
594     cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
595     captureStdOut = nullptr;
596     captureStdErr = nullptr;
597   } else if (outputflag == OUTPUT_MERGE ||
598              (captureStdErr && captureStdErr == captureStdOut)) {
599     cmsysProcess_SetOption(cp, cmsysProcess_Option_MergeOutput, 1);
600     captureStdErr = nullptr;
601   }
602   assert(!captureStdErr || captureStdErr != captureStdOut);
603
604   cmsysProcess_SetTimeout(cp, timeout.count());
605   cmsysProcess_Execute(cp);
606
607   std::vector<char> tempStdOut;
608   std::vector<char> tempStdErr;
609   char* data;
610   int length;
611   int pipe;
612   cmProcessOutput processOutput(encoding);
613   std::string strdata;
614   if (outputflag != OUTPUT_PASSTHROUGH &&
615       (captureStdOut || captureStdErr || outputflag != OUTPUT_NONE)) {
616     while ((pipe = cmsysProcess_WaitForData(cp, &data, &length, nullptr)) >
617            0) {
618       // Translate NULL characters in the output into valid text.
619       for (int i = 0; i < length; ++i) {
620         if (data[i] == '\0') {
621           data[i] = ' ';
622         }
623       }
624
625       if (pipe == cmsysProcess_Pipe_STDOUT) {
626         if (outputflag != OUTPUT_NONE) {
627           processOutput.DecodeText(data, length, strdata, 1);
628           cmSystemTools::Stdout(strdata);
629         }
630         if (captureStdOut) {
631           cm::append(tempStdOut, data, data + length);
632         }
633       } else if (pipe == cmsysProcess_Pipe_STDERR) {
634         if (outputflag != OUTPUT_NONE) {
635           processOutput.DecodeText(data, length, strdata, 2);
636           cmSystemTools::Stderr(strdata);
637         }
638         if (captureStdErr) {
639           cm::append(tempStdErr, data, data + length);
640         }
641       }
642     }
643
644     if (outputflag != OUTPUT_NONE) {
645       processOutput.DecodeText(std::string(), strdata, 1);
646       if (!strdata.empty()) {
647         cmSystemTools::Stdout(strdata);
648       }
649       processOutput.DecodeText(std::string(), strdata, 2);
650       if (!strdata.empty()) {
651         cmSystemTools::Stderr(strdata);
652       }
653     }
654   }
655
656   cmsysProcess_WaitForExit(cp, nullptr);
657
658   if (captureStdOut) {
659     captureStdOut->assign(tempStdOut.begin(), tempStdOut.end());
660     processOutput.DecodeText(*captureStdOut, *captureStdOut);
661   }
662   if (captureStdErr) {
663     captureStdErr->assign(tempStdErr.begin(), tempStdErr.end());
664     processOutput.DecodeText(*captureStdErr, *captureStdErr);
665   }
666
667   bool result = true;
668   if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
669     if (retVal) {
670       *retVal = cmsysProcess_GetExitValue(cp);
671     } else {
672       if (cmsysProcess_GetExitValue(cp) != 0) {
673         result = false;
674       }
675     }
676   } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) {
677     const char* exception_str = cmsysProcess_GetExceptionString(cp);
678     if (outputflag != OUTPUT_NONE) {
679       std::cerr << exception_str << std::endl;
680     }
681     if (captureStdErr) {
682       captureStdErr->append(exception_str, strlen(exception_str));
683     } else if (captureStdOut) {
684       captureStdOut->append(exception_str, strlen(exception_str));
685     }
686     result = false;
687   } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) {
688     const char* error_str = cmsysProcess_GetErrorString(cp);
689     if (outputflag != OUTPUT_NONE) {
690       std::cerr << error_str << std::endl;
691     }
692     if (captureStdErr) {
693       captureStdErr->append(error_str, strlen(error_str));
694     } else if (captureStdOut) {
695       captureStdOut->append(error_str, strlen(error_str));
696     }
697     result = false;
698   } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) {
699     const char* error_str = "Process terminated due to timeout\n";
700     if (outputflag != OUTPUT_NONE) {
701       std::cerr << error_str << std::endl;
702     }
703     if (captureStdErr) {
704       captureStdErr->append(error_str, strlen(error_str));
705     }
706     result = false;
707   }
708
709   cmsysProcess_Delete(cp);
710   return result;
711 }
712
713 bool cmSystemTools::RunSingleCommand(const std::string& command,
714                                      std::string* captureStdOut,
715                                      std::string* captureStdErr, int* retVal,
716                                      const char* dir, OutputOption outputflag,
717                                      cmDuration timeout)
718 {
719   if (s_DisableRunCommandOutput) {
720     outputflag = OUTPUT_NONE;
721   }
722
723   std::vector<std::string> args = cmSystemTools::ParseArguments(command);
724
725   if (args.empty()) {
726     return false;
727   }
728   return cmSystemTools::RunSingleCommand(args, captureStdOut, captureStdErr,
729                                          retVal, dir, outputflag, timeout);
730 }
731
732 std::string cmSystemTools::PrintSingleCommand(
733   std::vector<std::string> const& command)
734 {
735   if (command.empty()) {
736     return std::string();
737   }
738
739   return cmWrap('"', command, '"', " ");
740 }
741
742 bool cmSystemTools::DoesFileExistWithExtensions(
743   const std::string& name, const std::vector<std::string>& headerExts)
744 {
745   std::string hname;
746
747   for (std::string const& headerExt : headerExts) {
748     hname = cmStrCat(name, '.', headerExt);
749     if (cmSystemTools::FileExists(hname)) {
750       return true;
751     }
752   }
753   return false;
754 }
755
756 std::string cmSystemTools::FileExistsInParentDirectories(
757   const std::string& fname, const std::string& directory,
758   const std::string& toplevel)
759 {
760   std::string file = fname;
761   cmSystemTools::ConvertToUnixSlashes(file);
762   std::string dir = directory;
763   cmSystemTools::ConvertToUnixSlashes(dir);
764   std::string prevDir;
765   while (dir != prevDir) {
766     std::string path = cmStrCat(dir, "/", file);
767     if (cmSystemTools::FileExists(path)) {
768       return path;
769     }
770     if (dir.size() < toplevel.size()) {
771       break;
772     }
773     prevDir = dir;
774     dir = cmSystemTools::GetParentDirectory(dir);
775   }
776   return "";
777 }
778
779 #ifdef _WIN32
780 namespace {
781
782 /* Helper class to save and restore the specified file (or directory)
783    attribute bits. Instantiate this class as an automatic variable on the
784    stack. Its constructor saves a copy of the file attributes, and then its
785    destructor restores the original attribute settings.  */
786 class SaveRestoreFileAttributes
787 {
788 public:
789   SaveRestoreFileAttributes(std::wstring const& path,
790                             uint32_t file_attrs_to_set);
791   ~SaveRestoreFileAttributes();
792
793   SaveRestoreFileAttributes(SaveRestoreFileAttributes const&) = delete;
794   SaveRestoreFileAttributes& operator=(SaveRestoreFileAttributes const&) =
795     delete;
796
797   void SetPath(std::wstring const& path) { path_ = path; }
798
799 private:
800   std::wstring path_;
801   uint32_t original_attr_bits_;
802 };
803
804 SaveRestoreFileAttributes::SaveRestoreFileAttributes(
805   std::wstring const& path, uint32_t file_attrs_to_set)
806   : path_(path)
807   , original_attr_bits_(0)
808 {
809   // Set the specified attributes for the source file/directory.
810   original_attr_bits_ = GetFileAttributesW(path_.c_str());
811   if ((INVALID_FILE_ATTRIBUTES != original_attr_bits_) &&
812       ((file_attrs_to_set & original_attr_bits_) != file_attrs_to_set)) {
813     SetFileAttributesW(path_.c_str(), original_attr_bits_ | file_attrs_to_set);
814   }
815 }
816
817 // We set attribute bits.  Now we need to restore their original state.
818 SaveRestoreFileAttributes::~SaveRestoreFileAttributes()
819 {
820   DWORD last_error = GetLastError();
821   // Verify or restore the original attributes.
822   const DWORD source_attr_bits = GetFileAttributesW(path_.c_str());
823   if (INVALID_FILE_ATTRIBUTES != source_attr_bits) {
824     if (original_attr_bits_ != source_attr_bits) {
825       // The file still exists, and its attributes aren't our saved values.
826       // Time to restore them.
827       SetFileAttributesW(path_.c_str(), original_attr_bits_);
828     }
829   }
830   SetLastError(last_error);
831 }
832
833 struct WindowsFileRetryInit
834 {
835   cmSystemTools::WindowsFileRetry Retry;
836   bool Explicit;
837 };
838
839 WindowsFileRetryInit InitWindowsFileRetry(wchar_t const* const values[2],
840                                           unsigned int const defaults[2])
841 {
842   unsigned int data[2] = { 0, 0 };
843   HKEY const keys[2] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE };
844   for (int k = 0; k < 2; ++k) {
845     HKEY hKey;
846     if (RegOpenKeyExW(keys[k], L"Software\\Kitware\\CMake\\Config", 0,
847                       KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
848       for (int v = 0; v < 2; ++v) {
849         DWORD dwData, dwType, dwSize = 4;
850         if (!data[v] &&
851             RegQueryValueExW(hKey, values[v], 0, &dwType, (BYTE*)&dwData,
852                              &dwSize) == ERROR_SUCCESS &&
853             dwType == REG_DWORD && dwSize == 4) {
854           data[v] = static_cast<unsigned int>(dwData);
855         }
856       }
857       RegCloseKey(hKey);
858     }
859   }
860   WindowsFileRetryInit init;
861   init.Explicit = data[0] || data[1];
862   init.Retry.Count = data[0] ? data[0] : defaults[0];
863   init.Retry.Delay = data[1] ? data[1] : defaults[1];
864   return init;
865 }
866
867 WindowsFileRetryInit InitWindowsFileRetry()
868 {
869   static wchar_t const* const values[2] = { L"FilesystemRetryCount",
870                                             L"FilesystemRetryDelay" };
871   static unsigned int const defaults[2] = { 5, 500 };
872   return InitWindowsFileRetry(values, defaults);
873 }
874
875 WindowsFileRetryInit InitWindowsDirectoryRetry()
876 {
877   static wchar_t const* const values[2] = { L"FilesystemDirectoryRetryCount",
878                                             L"FilesystemDirectoryRetryDelay" };
879   static unsigned int const defaults[2] = { 120, 500 };
880   WindowsFileRetryInit dirInit = InitWindowsFileRetry(values, defaults);
881   if (dirInit.Explicit) {
882     return dirInit;
883   }
884   WindowsFileRetryInit fileInit = InitWindowsFileRetry();
885   if (fileInit.Explicit) {
886     return fileInit;
887   }
888   return dirInit;
889 }
890
891 cmSystemTools::WindowsFileRetry GetWindowsRetry(std::wstring const& path)
892 {
893   // If we are performing a directory operation, then try and get the
894   // appropriate timing info.
895   DWORD const attrs = GetFileAttributesW(path.c_str());
896   if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
897     return cmSystemTools::GetWindowsDirectoryRetry();
898   }
899   return cmSystemTools::GetWindowsFileRetry();
900 }
901
902 } // end of anonymous namespace
903
904 cmSystemTools::WindowsFileRetry cmSystemTools::GetWindowsFileRetry()
905 {
906   static WindowsFileRetry retry = InitWindowsFileRetry().Retry;
907   return retry;
908 }
909
910 cmSystemTools::WindowsFileRetry cmSystemTools::GetWindowsDirectoryRetry()
911 {
912   static cmSystemTools::WindowsFileRetry retry =
913     InitWindowsDirectoryRetry().Retry;
914   return retry;
915 }
916
917 cmSystemTools::WindowsVersion cmSystemTools::GetWindowsVersion()
918 {
919   /* Windows version number data.  */
920   OSVERSIONINFOEXW osviex;
921   ZeroMemory(&osviex, sizeof(osviex));
922   osviex.dwOSVersionInfoSize = sizeof(osviex);
923
924 #  ifdef CM_WINDOWS_DEPRECATED_GetVersionEx
925 #    pragma warning(push)
926 #    ifdef __INTEL_COMPILER
927 #      pragma warning(disable : 1478)
928 #    elif defined __clang__
929 #      pragma clang diagnostic push
930 #      pragma clang diagnostic ignored "-Wdeprecated-declarations"
931 #    else
932 #      pragma warning(disable : 4996)
933 #    endif
934 #  endif
935   GetVersionExW((OSVERSIONINFOW*)&osviex);
936 #  ifdef CM_WINDOWS_DEPRECATED_GetVersionEx
937 #    ifdef __clang__
938 #      pragma clang diagnostic pop
939 #    else
940 #      pragma warning(pop)
941 #    endif
942 #  endif
943
944   WindowsVersion result;
945   result.dwMajorVersion = osviex.dwMajorVersion;
946   result.dwMinorVersion = osviex.dwMinorVersion;
947   result.dwBuildNumber = osviex.dwBuildNumber;
948   return result;
949 }
950 #endif
951
952 std::string cmSystemTools::GetRealPathResolvingWindowsSubst(
953   const std::string& path, std::string* errorMessage)
954 {
955 #ifdef _WIN32
956   // uv_fs_realpath uses Windows Vista API so fallback to kwsys if not found
957   std::string resolved_path;
958   uv_fs_t req;
959   int err = uv_fs_realpath(NULL, &req, path.c_str(), NULL);
960   if (!err) {
961     resolved_path = std::string((char*)req.ptr);
962     cmSystemTools::ConvertToUnixSlashes(resolved_path);
963     // Normalize to upper-case drive letter as GetActualCaseForPath does.
964     if (resolved_path.size() > 1 && resolved_path[1] == ':') {
965       resolved_path[0] = toupper(resolved_path[0]);
966     }
967   } else if (err == UV_ENOSYS) {
968     resolved_path = cmsys::SystemTools::GetRealPath(path, errorMessage);
969   } else if (errorMessage) {
970     LPSTR message = NULL;
971     DWORD size = FormatMessageA(
972       FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
973         FORMAT_MESSAGE_IGNORE_INSERTS,
974       NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&message, 0,
975       NULL);
976     *errorMessage = std::string(message, size);
977     LocalFree(message);
978
979     resolved_path = "";
980   } else {
981     resolved_path = path;
982   }
983   return resolved_path;
984 #else
985   return cmsys::SystemTools::GetRealPath(path, errorMessage);
986 #endif
987 }
988
989 void cmSystemTools::InitializeLibUV()
990 {
991 #if defined(_WIN32)
992   // Perform libuv one-time initialization now, and then un-do its
993   // global _fmode setting so that using libuv does not change the
994   // default file text/binary mode.  See libuv issue 840.
995   if (uv_loop_t* loop = uv_default_loop()) {
996     uv_loop_close(loop);
997   }
998 #  ifdef _MSC_VER
999   _set_fmode(_O_TEXT);
1000 #  else
1001   _fmode = _O_TEXT;
1002 #  endif
1003   // Replace libuv's report handler with our own to suppress popups.
1004   cmSystemTools::EnableMSVCDebugHook();
1005 #endif
1006 }
1007
1008 #if defined(_WIN32)
1009 #  include <random>
1010
1011 #  include <wctype.h>
1012 #  ifdef _MSC_VER
1013 using mode_t = cmSystemTools::SystemTools::mode_t;
1014 #  endif
1015 #else
1016 #  include <sys/stat.h>
1017 #endif
1018
1019 inline int Mkdir(const char* dir, const mode_t* mode)
1020 {
1021 #if defined(_WIN32)
1022   int ret = _wmkdir(cmSystemTools::ConvertToWindowsExtendedPath(dir).c_str());
1023   if (ret == 0 && mode)
1024     cmSystemTools::SystemTools::SetPermissions(dir, *mode);
1025   return ret;
1026 #else
1027   return mkdir(dir, mode ? *mode : 0777);
1028 #endif
1029 }
1030
1031 cmsys::Status cmSystemTools::MakeTempDirectory(std::string& path,
1032                                                const mode_t* mode)
1033 {
1034   if (path.empty()) {
1035     return cmsys::Status::POSIX(EINVAL);
1036   }
1037   return cmSystemTools::MakeTempDirectory(&path.front(), mode);
1038 }
1039
1040 cmsys::Status cmSystemTools::MakeTempDirectory(char* path, const mode_t* mode)
1041 {
1042   if (!path) {
1043     return cmsys::Status::POSIX(EINVAL);
1044   }
1045
1046   // verify that path ends with "XXXXXX"
1047   const auto l = std::strlen(path);
1048   if (!cmHasLiteralSuffix(cm::string_view{ path, l }, "XXXXXX")) {
1049     return cmsys::Status::POSIX(EINVAL);
1050   }
1051
1052   // create parent directories
1053   auto* sep = path;
1054   while ((sep = strchr(sep, '/'))) {
1055     // all underlying functions use C strings,
1056     // so temporarily end the string here
1057     *sep = '\0';
1058     Mkdir(path, mode);
1059
1060     *sep = '/';
1061     ++sep;
1062   }
1063
1064 #ifdef _WIN32
1065   const int nchars = 36;
1066   const char chars[nchars + 1] = "abcdefghijklmnopqrstuvwxyz0123456789";
1067
1068   std::random_device rd;
1069   std::mt19937 rg{ rd() };
1070   std::uniform_int_distribution<int> dist{ 0, nchars - 1 };
1071
1072   for (auto tries = 100; tries; --tries) {
1073     for (auto n = l - 6; n < l; ++n) {
1074       path[n] = chars[dist(rg)];
1075     }
1076     if (Mkdir(path, mode) == 0) {
1077       return cmsys::Status::Success();
1078     } else if (errno != EEXIST) {
1079       return cmsys::Status::POSIX_errno();
1080     }
1081   }
1082   return cmsys::Status::POSIX(EAGAIN);
1083 #else
1084   if (mkdtemp(path)) {
1085     if (mode) {
1086       chmod(path, *mode);
1087     }
1088   } else {
1089     return cmsys::Status::POSIX_errno();
1090   }
1091   return cmsys::Status::Success();
1092 #endif
1093 }
1094
1095 #ifdef _WIN32
1096 namespace {
1097 bool cmMoveFile(std::wstring const& oldname, std::wstring const& newname,
1098                 cmSystemTools::Replace replace)
1099 {
1100   // Not only ignore any previous error, but clear any memory of it.
1101   SetLastError(0);
1102
1103   DWORD flags = 0;
1104   if (replace == cmSystemTools::Replace::Yes) {
1105     // Use MOVEFILE_REPLACE_EXISTING to replace an existing destination file.
1106     flags = flags | MOVEFILE_REPLACE_EXISTING;
1107   }
1108
1109   return MoveFileExW(oldname.c_str(), newname.c_str(), flags);
1110 }
1111 }
1112 #endif
1113
1114 bool cmSystemTools::CopySingleFile(const std::string& oldname,
1115                                    const std::string& newname)
1116 {
1117   return cmSystemTools::CopySingleFile(oldname, newname, CopyWhen::Always) ==
1118     CopyResult::Success;
1119 }
1120
1121 cmSystemTools::CopyResult cmSystemTools::CopySingleFile(
1122   std::string const& oldname, std::string const& newname, CopyWhen when,
1123   std::string* err)
1124 {
1125   switch (when) {
1126     case CopyWhen::Always:
1127       break;
1128     case CopyWhen::OnlyIfDifferent:
1129       if (!FilesDiffer(oldname, newname)) {
1130         return CopyResult::Success;
1131       }
1132       break;
1133   }
1134
1135   mode_t perm = 0;
1136   cmsys::Status perms = SystemTools::GetPermissions(oldname, perm);
1137
1138   // If files are the same do not copy
1139   if (SystemTools::SameFile(oldname, newname)) {
1140     return CopyResult::Success;
1141   }
1142
1143   cmsys::Status status;
1144   status = cmsys::SystemTools::CloneFileContent(oldname, newname);
1145   if (!status) {
1146     // if cloning did not succeed, fall back to blockwise copy
1147     status = cmsys::SystemTools::CopyFileContentBlockwise(oldname, newname);
1148   }
1149   if (!status) {
1150     if (err) {
1151       *err = status.GetString();
1152     }
1153     return CopyResult::Failure;
1154   }
1155   if (perms) {
1156     status = SystemTools::SetPermissions(newname, perm);
1157     if (!status) {
1158       if (err) {
1159         *err = status.GetString();
1160       }
1161       return CopyResult::Failure;
1162     }
1163   }
1164   return CopyResult::Success;
1165 }
1166
1167 bool cmSystemTools::RenameFile(const std::string& oldname,
1168                                const std::string& newname)
1169 {
1170   return cmSystemTools::RenameFile(oldname, newname, Replace::Yes) ==
1171     RenameResult::Success;
1172 }
1173
1174 cmSystemTools::RenameResult cmSystemTools::RenameFile(
1175   std::string const& oldname, std::string const& newname, Replace replace,
1176   std::string* err)
1177 {
1178 #ifdef _WIN32
1179 #  ifndef INVALID_FILE_ATTRIBUTES
1180 #    define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
1181 #  endif
1182   std::wstring const oldname_wstr =
1183     SystemTools::ConvertToWindowsExtendedPath(oldname);
1184   std::wstring const newname_wstr =
1185     SystemTools::ConvertToWindowsExtendedPath(newname);
1186
1187   /* Windows MoveFileEx may not replace read-only or in-use files.  If it
1188      fails then remove the read-only attribute from any existing destination.
1189      Try multiple times since we may be racing against another process
1190      creating/opening the destination file just before our MoveFileEx.  */
1191   WindowsFileRetry retry = GetWindowsRetry(oldname_wstr);
1192
1193   // Use RAII to set the attribute bit blocking Microsoft Search Indexing,
1194   // and restore the previous value upon return.
1195   SaveRestoreFileAttributes save_restore_file_attributes(
1196     oldname_wstr, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
1197
1198   DWORD move_last_error = 0;
1199   while (!cmMoveFile(oldname_wstr, newname_wstr, replace) && --retry.Count) {
1200     move_last_error = GetLastError();
1201
1202     // There was no error ==> the operation is not yet complete.
1203     if (move_last_error == NO_ERROR) {
1204       break;
1205     }
1206
1207     // Try again only if failure was due to access/sharing permissions.
1208     // Most often ERROR_ACCESS_DENIED (a.k.a. I/O error) for a directory, and
1209     // ERROR_SHARING_VIOLATION for a file, are caused by one of the following:
1210     // 1) Anti-Virus Software
1211     // 2) Windows Search Indexer
1212     // 3) Windows Explorer has an associated directory already opened.
1213     if (move_last_error != ERROR_ACCESS_DENIED &&
1214         move_last_error != ERROR_SHARING_VIOLATION) {
1215       if (replace == Replace::No && move_last_error == ERROR_ALREADY_EXISTS) {
1216         return RenameResult::NoReplace;
1217       }
1218       if (err) {
1219         *err = cmsys::Status::Windows(move_last_error).GetString();
1220       }
1221       return RenameResult::Failure;
1222     }
1223
1224     DWORD const attrs = GetFileAttributesW(newname_wstr.c_str());
1225     if ((attrs != INVALID_FILE_ATTRIBUTES) &&
1226         (attrs & FILE_ATTRIBUTE_READONLY) &&
1227         // FILE_ATTRIBUTE_READONLY is not honored on directories.
1228         !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
1229       // Remove the read-only attribute from the destination file.
1230       SetFileAttributesW(newname_wstr.c_str(),
1231                          attrs & ~FILE_ATTRIBUTE_READONLY);
1232     } else {
1233       // The file may be temporarily in use so wait a bit.
1234       cmSystemTools::Delay(retry.Delay);
1235     }
1236   }
1237
1238   // If we were successful, then there was no error.
1239   if (retry.Count > 0) {
1240     move_last_error = 0;
1241     // Restore the attributes on the new name.
1242     save_restore_file_attributes.SetPath(newname_wstr);
1243   }
1244   SetLastError(move_last_error);
1245   if (retry.Count > 0) {
1246     return RenameResult::Success;
1247   }
1248   if (replace == Replace::No && GetLastError() == ERROR_ALREADY_EXISTS) {
1249     return RenameResult::NoReplace;
1250   }
1251   if (err) {
1252     *err = cmsys::Status::Windows_GetLastError().GetString();
1253   }
1254   return RenameResult::Failure;
1255 #else
1256   // On UNIX we have OS-provided calls to create 'newname' atomically.
1257   if (replace == Replace::No) {
1258     if (link(oldname.c_str(), newname.c_str()) == 0) {
1259       return RenameResult::Success;
1260     }
1261     if (errno == EEXIST) {
1262       return RenameResult::NoReplace;
1263     }
1264     if (err) {
1265       *err = cmsys::Status::POSIX_errno().GetString();
1266     }
1267     return RenameResult::Failure;
1268   }
1269   if (rename(oldname.c_str(), newname.c_str()) == 0) {
1270     return RenameResult::Success;
1271   }
1272   if (err) {
1273     *err = cmsys::Status::POSIX_errno().GetString();
1274   }
1275   return RenameResult::Failure;
1276 #endif
1277 }
1278
1279 void cmSystemTools::MoveFileIfDifferent(const std::string& source,
1280                                         const std::string& destination)
1281 {
1282   if (FilesDiffer(source, destination)) {
1283     if (RenameFile(source, destination)) {
1284       return;
1285     }
1286     CopyFileAlways(source, destination);
1287   }
1288   RemoveFile(source);
1289 }
1290
1291 #ifndef CMAKE_BOOTSTRAP
1292 std::string cmSystemTools::ComputeFileHash(const std::string& source,
1293                                            cmCryptoHash::Algo algo)
1294 {
1295   cmCryptoHash hash(algo);
1296   return hash.HashFile(source);
1297 }
1298
1299 std::string cmSystemTools::ComputeStringMD5(const std::string& input)
1300 {
1301   cmCryptoHash md5(cmCryptoHash::AlgoMD5);
1302   return md5.HashString(input);
1303 }
1304
1305 #  ifdef _WIN32
1306 std::string cmSystemTools::ComputeCertificateThumbprint(
1307   const std::string& source)
1308 {
1309   std::string thumbprint;
1310
1311   CRYPT_INTEGER_BLOB cryptBlob;
1312   HCERTSTORE certStore = NULL;
1313   PCCERT_CONTEXT certContext = NULL;
1314
1315   HANDLE certFile = CreateFileW(
1316     cmsys::Encoding::ToWide(source.c_str()).c_str(), GENERIC_READ,
1317     FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1318
1319   if (certFile != INVALID_HANDLE_VALUE && certFile != NULL) {
1320     DWORD fileSize = GetFileSize(certFile, NULL);
1321     if (fileSize != INVALID_FILE_SIZE) {
1322       auto certData = cm::make_unique<BYTE[]>(fileSize);
1323       if (certData != NULL) {
1324         DWORD dwRead = 0;
1325         if (ReadFile(certFile, certData.get(), fileSize, &dwRead, NULL)) {
1326           cryptBlob.cbData = fileSize;
1327           cryptBlob.pbData = certData.get();
1328
1329           // Verify that this is a valid cert
1330           if (PFXIsPFXBlob(&cryptBlob)) {
1331             // Open the certificate as a store
1332             certStore = PFXImportCertStore(&cryptBlob, NULL, CRYPT_EXPORTABLE);
1333             if (certStore != NULL) {
1334               // There should only be 1 cert.
1335               certContext =
1336                 CertEnumCertificatesInStore(certStore, certContext);
1337               if (certContext != NULL) {
1338                 // The hash is 20 bytes
1339                 BYTE hashData[20];
1340                 DWORD hashLength = 20;
1341
1342                 // Buffer to print the hash. Each byte takes 2 chars +
1343                 // terminating character
1344                 char hashPrint[41];
1345                 char* pHashPrint = hashPrint;
1346                 // Get the hash property from the certificate
1347                 if (CertGetCertificateContextProperty(
1348                       certContext, CERT_HASH_PROP_ID, hashData, &hashLength)) {
1349                   for (DWORD i = 0; i < hashLength; i++) {
1350                     // Convert each byte to hexadecimal
1351                     snprintf(pHashPrint, 3, "%02X", hashData[i]);
1352                     pHashPrint += 2;
1353                   }
1354                   *pHashPrint = '\0';
1355                   thumbprint = hashPrint;
1356                 }
1357                 CertFreeCertificateContext(certContext);
1358               }
1359               CertCloseStore(certStore, 0);
1360             }
1361           }
1362         }
1363       }
1364     }
1365     CloseHandle(certFile);
1366   }
1367
1368   return thumbprint;
1369 }
1370 #  endif
1371 #endif
1372
1373 void cmSystemTools::Glob(const std::string& directory,
1374                          const std::string& regexp,
1375                          std::vector<std::string>& files)
1376 {
1377   cmsys::Directory d;
1378   cmsys::RegularExpression reg(regexp.c_str());
1379
1380   if (d.Load(directory)) {
1381     size_t numf;
1382     unsigned int i;
1383     numf = d.GetNumberOfFiles();
1384     for (i = 0; i < numf; i++) {
1385       std::string fname = d.GetFile(i);
1386       if (reg.find(fname)) {
1387         files.push_back(std::move(fname));
1388       }
1389     }
1390   }
1391 }
1392
1393 void cmSystemTools::GlobDirs(const std::string& path,
1394                              std::vector<std::string>& files)
1395 {
1396   std::string::size_type pos = path.find("/*");
1397   if (pos == std::string::npos) {
1398     files.push_back(path);
1399     return;
1400   }
1401   std::string startPath = path.substr(0, pos);
1402   std::string finishPath = path.substr(pos + 2);
1403
1404   cmsys::Directory d;
1405   if (d.Load(startPath)) {
1406     for (unsigned int i = 0; i < d.GetNumberOfFiles(); ++i) {
1407       if ((std::string(d.GetFile(i)) != ".") &&
1408           (std::string(d.GetFile(i)) != "..")) {
1409         std::string fname = cmStrCat(startPath, '/', d.GetFile(i));
1410         if (cmSystemTools::FileIsDirectory(fname)) {
1411           fname += finishPath;
1412           cmSystemTools::GlobDirs(fname, files);
1413         }
1414       }
1415     }
1416   }
1417 }
1418
1419 bool cmSystemTools::SimpleGlob(const std::string& glob,
1420                                std::vector<std::string>& files,
1421                                int type /* = 0 */)
1422 {
1423   files.clear();
1424   if (glob.back() != '*') {
1425     return false;
1426   }
1427   std::string path = cmSystemTools::GetFilenamePath(glob);
1428   std::string ppath = cmSystemTools::GetFilenameName(glob);
1429   ppath = ppath.substr(0, ppath.size() - 1);
1430   if (path.empty()) {
1431     path = "/";
1432   }
1433
1434   bool res = false;
1435   cmsys::Directory d;
1436   if (d.Load(path)) {
1437     for (unsigned int i = 0; i < d.GetNumberOfFiles(); ++i) {
1438       if ((std::string(d.GetFile(i)) != ".") &&
1439           (std::string(d.GetFile(i)) != "..")) {
1440         std::string fname = path;
1441         if (path.back() != '/') {
1442           fname += "/";
1443         }
1444         fname += d.GetFile(i);
1445         std::string sfname = d.GetFile(i);
1446         if (type > 0 && cmSystemTools::FileIsDirectory(fname)) {
1447           continue;
1448         }
1449         if (type < 0 && !cmSystemTools::FileIsDirectory(fname)) {
1450           continue;
1451         }
1452         if (cmHasPrefix(sfname, ppath)) {
1453           files.push_back(fname);
1454           res = true;
1455         }
1456       }
1457     }
1458   }
1459   return res;
1460 }
1461
1462 std::string cmSystemTools::ConvertToOutputPath(std::string const& path)
1463 {
1464 #if defined(_WIN32) && !defined(__CYGWIN__)
1465   if (s_ForceUnixPaths) {
1466     return cmSystemTools::ConvertToUnixOutputPath(path);
1467   }
1468   return cmSystemTools::ConvertToWindowsOutputPath(path);
1469 #else
1470   return cmSystemTools::ConvertToUnixOutputPath(path);
1471 #endif
1472 }
1473
1474 void cmSystemTools::ConvertToOutputSlashes(std::string& path)
1475 {
1476 #if defined(_WIN32) && !defined(__CYGWIN__)
1477   if (!s_ForceUnixPaths) {
1478     // Convert to windows slashes.
1479     std::string::size_type pos = 0;
1480     while ((pos = path.find('/', pos)) != std::string::npos) {
1481       path[pos++] = '\\';
1482     }
1483   }
1484 #else
1485   static_cast<void>(path);
1486 #endif
1487 }
1488
1489 void cmSystemTools::ConvertToLongPath(std::string& path)
1490 {
1491 #if defined(_WIN32) && !defined(__CYGWIN__)
1492   // Try to convert path to a long path only if the path contains character '~'
1493   if (path.find('~') == std::string::npos) {
1494     return;
1495   }
1496
1497   std::wstring wPath = cmsys::Encoding::ToWide(path);
1498   DWORD ret = GetLongPathNameW(wPath.c_str(), nullptr, 0);
1499   std::vector<wchar_t> buffer(ret);
1500   if (ret != 0) {
1501     ret = GetLongPathNameW(wPath.c_str(), buffer.data(),
1502                            static_cast<DWORD>(buffer.size()));
1503   }
1504
1505   if (ret != 0) {
1506     path = cmsys::Encoding::ToNarrow(buffer.data());
1507   }
1508 #else
1509   static_cast<void>(path);
1510 #endif
1511 }
1512
1513 std::string cmSystemTools::ConvertToRunCommandPath(const std::string& path)
1514 {
1515 #if defined(_WIN32) && !defined(__CYGWIN__)
1516   return cmSystemTools::ConvertToWindowsOutputPath(path);
1517 #else
1518   return cmSystemTools::ConvertToUnixOutputPath(path);
1519 #endif
1520 }
1521
1522 // compute the relative path from here to there
1523 std::string cmSystemTools::RelativePath(std::string const& local,
1524                                         std::string const& remote)
1525 {
1526   if (!cmSystemTools::FileIsFullPath(local)) {
1527     cmSystemTools::Error("RelativePath must be passed a full path to local: " +
1528                          local);
1529   }
1530   if (!cmSystemTools::FileIsFullPath(remote)) {
1531     cmSystemTools::Error(
1532       "RelativePath must be passed a full path to remote: " + remote);
1533   }
1534   return cmsys::SystemTools::RelativePath(local, remote);
1535 }
1536
1537 std::string cmSystemTools::ForceToRelativePath(std::string const& local_path,
1538                                                std::string const& remote_path)
1539 {
1540   // The paths should never be quoted.
1541   assert(local_path.front() != '\"');
1542   assert(remote_path.front() != '\"');
1543
1544   // The local path should never have a trailing slash except if it is just the
1545   // bare root directory
1546   assert(local_path.empty() || local_path.back() != '/' ||
1547          local_path.size() == 1 ||
1548          (local_path.size() == 3 && local_path[1] == ':' &&
1549           ((local_path[0] >= 'A' && local_path[0] <= 'Z') ||
1550            (local_path[0] >= 'a' && local_path[0] <= 'z'))));
1551
1552   // If the path is already relative then just return the path.
1553   if (!cmSystemTools::FileIsFullPath(remote_path)) {
1554     return remote_path;
1555   }
1556
1557   // Identify the longest shared path component between the remote
1558   // path and the local path.
1559   std::vector<std::string> local;
1560   cmSystemTools::SplitPath(local_path, local);
1561   std::vector<std::string> remote;
1562   cmSystemTools::SplitPath(remote_path, remote);
1563   unsigned int common = 0;
1564   while (common < remote.size() && common < local.size() &&
1565          cmSystemTools::ComparePath(remote[common], local[common])) {
1566     ++common;
1567   }
1568
1569   // If no part of the path is in common then return the full path.
1570   if (common == 0) {
1571     return remote_path;
1572   }
1573
1574   // If the entire path is in common then just return a ".".
1575   if (common == remote.size() && common == local.size()) {
1576     return ".";
1577   }
1578
1579   // If the entire path is in common except for a trailing slash then
1580   // just return a "./".
1581   if (common + 1 == remote.size() && remote[common].empty() &&
1582       common == local.size()) {
1583     return "./";
1584   }
1585
1586   // Construct the relative path.
1587   std::string relative;
1588
1589   // First add enough ../ to get up to the level of the shared portion
1590   // of the path.  Leave off the trailing slash.  Note that the last
1591   // component of local will never be empty because local should never
1592   // have a trailing slash.
1593   for (unsigned int i = common; i < local.size(); ++i) {
1594     relative += "..";
1595     if (i < local.size() - 1) {
1596       relative += "/";
1597     }
1598   }
1599
1600   // Now add the portion of the destination path that is not included
1601   // in the shared portion of the path.  Add a slash the first time
1602   // only if there was already something in the path.  If there was a
1603   // trailing slash in the input then the last iteration of the loop
1604   // will add a slash followed by an empty string which will preserve
1605   // the trailing slash in the output.
1606
1607   if (!relative.empty() && !remote.empty()) {
1608     relative += "/";
1609   }
1610   relative += cmJoin(cmMakeRange(remote).advance(common), "/");
1611
1612   // Finally return the path.
1613   return relative;
1614 }
1615
1616 std::string cmSystemTools::RelativeIfUnder(std::string const& top,
1617                                            std::string const& in)
1618 {
1619   std::string out;
1620   if (in == top) {
1621     out = ".";
1622   } else if (cmSystemTools::IsSubDirectory(in, top)) {
1623     out = in.substr(top.size() + 1);
1624   } else {
1625     out = in;
1626   }
1627   return out;
1628 }
1629
1630 #ifndef CMAKE_BOOTSTRAP
1631 bool cmSystemTools::UnsetEnv(const char* value)
1632 {
1633 #  if !defined(HAVE_UNSETENV)
1634   return cmSystemTools::UnPutEnv(value);
1635 #  else
1636   unsetenv(value);
1637   return true;
1638 #  endif
1639 }
1640
1641 std::vector<std::string> cmSystemTools::GetEnvironmentVariables()
1642 {
1643   std::vector<std::string> env;
1644   int cc;
1645 #  ifdef _WIN32
1646   // if program starts with main, _wenviron is initially NULL, call to
1647   // _wgetenv and create wide-character string environment
1648   _wgetenv(L"");
1649   for (cc = 0; _wenviron[cc]; ++cc) {
1650     env.emplace_back(cmsys::Encoding::ToNarrow(_wenviron[cc]));
1651   }
1652 #  else
1653   for (cc = 0; environ[cc]; ++cc) {
1654     env.emplace_back(environ[cc]);
1655   }
1656 #  endif
1657   return env;
1658 }
1659
1660 void cmSystemTools::AppendEnv(std::vector<std::string> const& env)
1661 {
1662   for (std::string const& eit : env) {
1663     cmSystemTools::PutEnv(eit);
1664   }
1665 }
1666
1667 void cmSystemTools::EnvDiff::AppendEnv(std::vector<std::string> const& env)
1668 {
1669   for (std::string const& eit : env) {
1670     this->PutEnv(eit);
1671   }
1672 }
1673
1674 void cmSystemTools::EnvDiff::PutEnv(const std::string& env)
1675 {
1676   auto const eq_loc = env.find('=');
1677   if (eq_loc != std::string::npos) {
1678     std::string name = env.substr(0, eq_loc);
1679     diff[name] = env.substr(eq_loc + 1);
1680   } else {
1681     this->UnPutEnv(env);
1682   }
1683 }
1684
1685 void cmSystemTools::EnvDiff::UnPutEnv(const std::string& env)
1686 {
1687   diff[env] = {};
1688 }
1689
1690 bool cmSystemTools::EnvDiff::ParseOperation(const std::string& envmod)
1691 {
1692   char path_sep = GetSystemPathlistSeparator();
1693
1694   auto apply_diff = [this](const std::string& name,
1695                            std::function<void(std::string&)> const& apply) {
1696     cm::optional<std::string> old_value = diff[name];
1697     std::string output;
1698     if (old_value) {
1699       output = *old_value;
1700     } else {
1701       const char* curval = cmSystemTools::GetEnv(name);
1702       if (curval) {
1703         output = curval;
1704       }
1705     }
1706     apply(output);
1707     diff[name] = output;
1708   };
1709
1710   // Split on `=`
1711   auto const eq_loc = envmod.find_first_of('=');
1712   if (eq_loc == std::string::npos) {
1713     cmSystemTools::Error(cmStrCat(
1714       "Error: Missing `=` after the variable name in: ", envmod, '\n'));
1715     return false;
1716   }
1717
1718   auto const name = envmod.substr(0, eq_loc);
1719
1720   // Split value on `:`
1721   auto const op_value_start = eq_loc + 1;
1722   auto const colon_loc = envmod.find_first_of(':', op_value_start);
1723   if (colon_loc == std::string::npos) {
1724     cmSystemTools::Error(
1725       cmStrCat("Error: Missing `:` after the operation in: ", envmod, '\n'));
1726     return false;
1727   }
1728   auto const op = envmod.substr(op_value_start, colon_loc - op_value_start);
1729
1730   auto const value_start = colon_loc + 1;
1731   auto const value = envmod.substr(value_start);
1732
1733   // Determine what to do with the operation.
1734   if (op == "reset"_s) {
1735     auto entry = diff.find(name);
1736     if (entry != diff.end()) {
1737       diff.erase(entry);
1738     }
1739   } else if (op == "set"_s) {
1740     diff[name] = value;
1741   } else if (op == "unset"_s) {
1742     diff[name] = {};
1743   } else if (op == "string_append"_s) {
1744     apply_diff(name, [&value](std::string& output) { output += value; });
1745   } else if (op == "string_prepend"_s) {
1746     apply_diff(name,
1747                [&value](std::string& output) { output.insert(0, value); });
1748   } else if (op == "path_list_append"_s) {
1749     apply_diff(name, [&value, path_sep](std::string& output) {
1750       if (!output.empty()) {
1751         output += path_sep;
1752       }
1753       output += value;
1754     });
1755   } else if (op == "path_list_prepend"_s) {
1756     apply_diff(name, [&value, path_sep](std::string& output) {
1757       if (!output.empty()) {
1758         output.insert(output.begin(), path_sep);
1759       }
1760       output.insert(0, value);
1761     });
1762   } else if (op == "cmake_list_append"_s) {
1763     apply_diff(name, [&value](std::string& output) {
1764       if (!output.empty()) {
1765         output += ';';
1766       }
1767       output += value;
1768     });
1769   } else if (op == "cmake_list_prepend"_s) {
1770     apply_diff(name, [&value](std::string& output) {
1771       if (!output.empty()) {
1772         output.insert(output.begin(), ';');
1773       }
1774       output.insert(0, value);
1775     });
1776   } else {
1777     cmSystemTools::Error(cmStrCat(
1778       "Error: Unrecognized environment manipulation argument: ", op, '\n'));
1779     return false;
1780   }
1781
1782   return true;
1783 }
1784
1785 void cmSystemTools::EnvDiff::ApplyToCurrentEnv(std::ostringstream* measurement)
1786 {
1787   for (auto const& env_apply : diff) {
1788     if (env_apply.second) {
1789       auto const env_update =
1790         cmStrCat(env_apply.first, '=', *env_apply.second);
1791       cmSystemTools::PutEnv(env_update);
1792       if (measurement) {
1793         *measurement << env_update << std::endl;
1794       }
1795     } else {
1796       cmSystemTools::UnsetEnv(env_apply.first.c_str());
1797       if (measurement) {
1798         // Signify that this variable is being actively unset
1799         *measurement << '#' << env_apply.first << "=\n";
1800       }
1801     }
1802   }
1803 }
1804
1805 cmSystemTools::SaveRestoreEnvironment::SaveRestoreEnvironment()
1806 {
1807   this->Env = cmSystemTools::GetEnvironmentVariables();
1808 }
1809
1810 cmSystemTools::SaveRestoreEnvironment::~SaveRestoreEnvironment()
1811 {
1812   // First clear everything in the current environment:
1813   std::vector<std::string> currentEnv = GetEnvironmentVariables();
1814   for (std::string var : currentEnv) {
1815     std::string::size_type pos = var.find('=');
1816     if (pos != std::string::npos) {
1817       var = var.substr(0, pos);
1818     }
1819
1820     cmSystemTools::UnsetEnv(var.c_str());
1821   }
1822
1823   // Then put back each entry from the original environment:
1824   cmSystemTools::AppendEnv(this->Env);
1825 }
1826 #endif
1827
1828 void cmSystemTools::EnableVSConsoleOutput()
1829 {
1830 #ifdef _WIN32
1831   // Visual Studio tools like devenv may not
1832   // display output to the console unless this environment variable is
1833   // set.  We need it to capture the output of these build tools.
1834   // Note for future work that one could pass "/out \\.\pipe\NAME" to
1835   // either of these executables where NAME is created with
1836   // CreateNamedPipe.  This would bypass the internal buffering of the
1837   // output and allow it to be captured on the fly.
1838   cmSystemTools::PutEnv("vsconsoleoutput=1");
1839
1840 #  ifndef CMAKE_BOOTSTRAP
1841   // VS sets an environment variable to tell MS tools like "cl" to report
1842   // output through a backdoor pipe instead of stdout/stderr.  Unset the
1843   // environment variable to close this backdoor for any path of process
1844   // invocations that passes through CMake so we can capture the output.
1845   cmSystemTools::UnsetEnv("VS_UNICODE_OUTPUT");
1846 #  endif
1847 #endif
1848 }
1849
1850 bool cmSystemTools::IsPathToFramework(const std::string& path)
1851 {
1852   return (cmSystemTools::FileIsFullPath(path) &&
1853           cmHasLiteralSuffix(path, ".framework"));
1854 }
1855
1856 bool cmSystemTools::IsPathToMacOSSharedLibrary(const std::string& path)
1857 {
1858   return (cmSystemTools::FileIsFullPath(path) &&
1859           cmHasLiteralSuffix(path, ".dylib"));
1860 }
1861
1862 bool cmSystemTools::CreateTar(const std::string& outFileName,
1863                               const std::vector<std::string>& files,
1864                               cmTarCompression compressType, bool verbose,
1865                               std::string const& mtime,
1866                               std::string const& format, int compressionLevel)
1867 {
1868 #if !defined(CMAKE_BOOTSTRAP)
1869   std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
1870   cmsys::ofstream fout(outFileName.c_str(), std::ios::out | std::ios::binary);
1871   if (!fout) {
1872     std::string e = cmStrCat("Cannot open output file \"", outFileName,
1873                              "\": ", cmSystemTools::GetLastSystemError());
1874     cmSystemTools::Error(e);
1875     return false;
1876   }
1877   cmArchiveWrite::Compress compress = cmArchiveWrite::CompressNone;
1878   switch (compressType) {
1879     case TarCompressGZip:
1880       compress = cmArchiveWrite::CompressGZip;
1881       break;
1882     case TarCompressBZip2:
1883       compress = cmArchiveWrite::CompressBZip2;
1884       break;
1885     case TarCompressXZ:
1886       compress = cmArchiveWrite::CompressXZ;
1887       break;
1888     case TarCompressZstd:
1889       compress = cmArchiveWrite::CompressZstd;
1890       break;
1891     case TarCompressNone:
1892       compress = cmArchiveWrite::CompressNone;
1893       break;
1894   }
1895
1896   cmArchiveWrite a(fout, compress, format.empty() ? "paxr" : format,
1897                    compressionLevel);
1898
1899   if (!a.Open()) {
1900     cmSystemTools::Error(a.GetError());
1901     return false;
1902   }
1903   a.SetMTime(mtime);
1904   a.SetVerbose(verbose);
1905   bool tarCreatedSuccessfully = true;
1906   for (auto path : files) {
1907     if (cmSystemTools::FileIsFullPath(path)) {
1908       // Get the relative path to the file.
1909       path = cmSystemTools::RelativePath(cwd, path);
1910     }
1911     if (!a.Add(path)) {
1912       cmSystemTools::Error(a.GetError());
1913       tarCreatedSuccessfully = false;
1914     }
1915   }
1916   return tarCreatedSuccessfully;
1917 #else
1918   (void)outFileName;
1919   (void)files;
1920   (void)verbose;
1921   return false;
1922 #endif
1923 }
1924
1925 #if !defined(CMAKE_BOOTSTRAP)
1926 namespace {
1927 #  define BSDTAR_FILESIZE_PRINTF "%lu"
1928 #  define BSDTAR_FILESIZE_TYPE unsigned long
1929 void list_item_verbose(FILE* out, struct archive_entry* entry)
1930 {
1931   char tmp[100];
1932   size_t w;
1933   const char* p;
1934   const char* fmt;
1935   time_t tim;
1936   static time_t now;
1937   size_t u_width = 6;
1938   size_t gs_width = 13;
1939
1940   /*
1941    * We avoid collecting the entire list in memory at once by
1942    * listing things as we see them.  However, that also means we can't
1943    * just pre-compute the field widths.  Instead, we start with guesses
1944    * and just widen them as necessary.  These numbers are completely
1945    * arbitrary.
1946    */
1947   if (!now) {
1948     time(&now);
1949   }
1950   fprintf(out, "%s %d ", archive_entry_strmode(entry),
1951           archive_entry_nlink(entry));
1952
1953   /* Use uname if it's present, else uid. */
1954   p = archive_entry_uname(entry);
1955   if ((p == nullptr) || (*p == '\0')) {
1956     snprintf(tmp, sizeof(tmp), "%lu ",
1957              static_cast<unsigned long>(archive_entry_uid(entry)));
1958     p = tmp;
1959   }
1960   w = strlen(p);
1961   if (w > u_width) {
1962     u_width = w;
1963   }
1964   fprintf(out, "%-*s ", static_cast<int>(u_width), p);
1965   /* Use gname if it's present, else gid. */
1966   p = archive_entry_gname(entry);
1967   if (p != nullptr && p[0] != '\0') {
1968     fprintf(out, "%s", p);
1969     w = strlen(p);
1970   } else {
1971     snprintf(tmp, sizeof(tmp), "%lu",
1972              static_cast<unsigned long>(archive_entry_gid(entry)));
1973     w = strlen(tmp);
1974     fprintf(out, "%s", tmp);
1975   }
1976
1977   /*
1978    * Print device number or file size, right-aligned so as to make
1979    * total width of group and devnum/filesize fields be gs_width.
1980    * If gs_width is too small, grow it.
1981    */
1982   if (archive_entry_filetype(entry) == AE_IFCHR ||
1983       archive_entry_filetype(entry) == AE_IFBLK) {
1984     unsigned long rdevmajor = archive_entry_rdevmajor(entry);
1985     unsigned long rdevminor = archive_entry_rdevminor(entry);
1986     snprintf(tmp, sizeof(tmp), "%lu,%lu", rdevmajor, rdevminor);
1987   } else {
1988     /*
1989      * Note the use of platform-dependent macros to format
1990      * the filesize here.  We need the format string and the
1991      * corresponding type for the cast.
1992      */
1993     snprintf(tmp, sizeof(tmp), BSDTAR_FILESIZE_PRINTF,
1994              static_cast<BSDTAR_FILESIZE_TYPE>(archive_entry_size(entry)));
1995   }
1996   if (w + strlen(tmp) >= gs_width) {
1997     gs_width = w + strlen(tmp) + 1;
1998   }
1999   fprintf(out, "%*s", static_cast<int>(gs_width - w), tmp);
2000
2001   /* Format the time using 'ls -l' conventions. */
2002   tim = archive_entry_mtime(entry);
2003 #  define HALF_YEAR ((time_t)365 * 86400 / 2)
2004 #  if defined(_WIN32) && !defined(__CYGWIN__)
2005 /* Windows' strftime function does not support %e format. */
2006 #    define DAY_FMT "%d"
2007 #  else
2008 #    define DAY_FMT "%e" /* Day number without leading zeros */
2009 #  endif
2010   if (tim < now - HALF_YEAR || tim > now + HALF_YEAR) {
2011     fmt = DAY_FMT " %b  %Y";
2012   } else {
2013     fmt = DAY_FMT " %b %H:%M";
2014   }
2015   strftime(tmp, sizeof(tmp), fmt, localtime(&tim));
2016   fprintf(out, " %s ", tmp);
2017   fprintf(out, "%s", cm_archive_entry_pathname(entry).c_str());
2018
2019   /* Extra information for links. */
2020   if (archive_entry_hardlink(entry)) /* Hard link */
2021   {
2022     fprintf(out, " link to %s", archive_entry_hardlink(entry));
2023   } else if (archive_entry_symlink(entry)) /* Symbolic link */
2024   {
2025     fprintf(out, " -> %s", archive_entry_symlink(entry));
2026   }
2027   fflush(out);
2028 }
2029
2030 void ArchiveError(const char* m1, struct archive* a)
2031 {
2032   std::string message(m1);
2033   const char* m2 = archive_error_string(a);
2034   if (m2) {
2035     message += m2;
2036   }
2037   cmSystemTools::Error(message);
2038 }
2039
2040 bool la_diagnostic(struct archive* ar, __LA_SSIZE_T r)
2041 {
2042   // See archive.h definition of ARCHIVE_OK for return values.
2043
2044   if (r >= ARCHIVE_OK) {
2045     return true;
2046   }
2047
2048   if (r >= ARCHIVE_WARN) {
2049     const char* warn = archive_error_string(ar);
2050     if (!warn) {
2051       warn = "unknown warning";
2052     }
2053     std::cerr << "cmake -E tar: warning: " << warn << '\n';
2054     return true;
2055   }
2056
2057   // Error.
2058   const char* err = archive_error_string(ar);
2059   if (!err) {
2060     err = "unknown error";
2061   }
2062   std::cerr << "cmake -E tar: error: " << err << '\n';
2063   return false;
2064 }
2065
2066 // Return 'true' on success
2067 bool copy_data(struct archive* ar, struct archive* aw)
2068 {
2069   long r;
2070   const void* buff;
2071   size_t size;
2072 #  if defined(ARCHIVE_VERSION_NUMBER) && ARCHIVE_VERSION_NUMBER >= 3000000
2073   __LA_INT64_T offset;
2074 #  else
2075   off_t offset;
2076 #  endif
2077
2078   for (;;) {
2079     // See archive.h definition of ARCHIVE_OK for return values.
2080     r = archive_read_data_block(ar, &buff, &size, &offset);
2081     if (r == ARCHIVE_EOF) {
2082       return true;
2083     }
2084     if (!la_diagnostic(ar, r)) {
2085       return false;
2086     }
2087     // See archive.h definition of ARCHIVE_OK for return values.
2088     __LA_SSIZE_T const w = archive_write_data_block(aw, buff, size, offset);
2089     if (!la_diagnostic(ar, w)) {
2090       return false;
2091     }
2092   }
2093 #  if !defined(__clang__) && !defined(__NVCOMPILER) && !defined(__HP_aCC)
2094   return false; /* this should not happen but it quiets some compilers */
2095 #  endif
2096 }
2097
2098 bool extract_tar(const std::string& outFileName,
2099                  const std::vector<std::string>& files, bool verbose,
2100                  cmSystemTools::cmTarExtractTimestamps extractTimestamps,
2101                  bool extract)
2102 {
2103   cmLocaleRAII localeRAII;
2104   static_cast<void>(localeRAII);
2105   struct archive* a = archive_read_new();
2106   struct archive* ext = archive_write_disk_new();
2107   archive_read_support_filter_all(a);
2108   archive_read_support_format_all(a);
2109   struct archive_entry* entry;
2110
2111   struct archive* matching = archive_match_new();
2112   if (matching == nullptr) {
2113     cmSystemTools::Error("Out of memory");
2114     return false;
2115   }
2116
2117   for (const auto& filename : files) {
2118     if (archive_match_include_pattern(matching, filename.c_str()) !=
2119         ARCHIVE_OK) {
2120       cmSystemTools::Error("Failed to add to inclusion list: " + filename);
2121       return false;
2122     }
2123   }
2124
2125   int r = cm_archive_read_open_file(a, outFileName.c_str(), 10240);
2126   if (r) {
2127     ArchiveError("Problem with archive_read_open_file(): ", a);
2128     archive_write_free(ext);
2129     archive_read_close(a);
2130     return false;
2131   }
2132   for (;;) {
2133     r = archive_read_next_header(a, &entry);
2134     if (r == ARCHIVE_EOF) {
2135       break;
2136     }
2137     if (r != ARCHIVE_OK) {
2138       ArchiveError("Problem with archive_read_next_header(): ", a);
2139       break;
2140     }
2141
2142     if (archive_match_excluded(matching, entry)) {
2143       continue;
2144     }
2145
2146     if (verbose) {
2147       if (extract) {
2148         cmSystemTools::Stdout("x ");
2149         cmSystemTools::Stdout(cm_archive_entry_pathname(entry));
2150       } else {
2151         list_item_verbose(stdout, entry);
2152       }
2153       cmSystemTools::Stdout("\n");
2154     } else if (!extract) {
2155       cmSystemTools::Stdout(cm_archive_entry_pathname(entry));
2156       cmSystemTools::Stdout("\n");
2157     }
2158     if (extract) {
2159       if (extractTimestamps == cmSystemTools::cmTarExtractTimestamps::Yes) {
2160         r = archive_write_disk_set_options(ext, ARCHIVE_EXTRACT_TIME);
2161         if (r != ARCHIVE_OK) {
2162           ArchiveError("Problem with archive_write_disk_set_options(): ", ext);
2163           break;
2164         }
2165       }
2166
2167       r = archive_write_header(ext, entry);
2168       if (r == ARCHIVE_OK) {
2169         if (!copy_data(a, ext)) {
2170           break;
2171         }
2172         r = archive_write_finish_entry(ext);
2173         if (r != ARCHIVE_OK) {
2174           ArchiveError("Problem with archive_write_finish_entry(): ", ext);
2175           break;
2176         }
2177       }
2178 #  ifdef _WIN32
2179       else if (const char* linktext = archive_entry_symlink(entry)) {
2180         std::cerr << "cmake -E tar: warning: skipping symbolic link \""
2181                   << cm_archive_entry_pathname(entry) << "\" -> \"" << linktext
2182                   << "\"." << std::endl;
2183       }
2184 #  endif
2185       else {
2186         ArchiveError("Problem with archive_write_header(): ", ext);
2187         cmSystemTools::Error("Current file: " +
2188                              cm_archive_entry_pathname(entry));
2189         break;
2190       }
2191     }
2192   }
2193
2194   bool error_occured = false;
2195   if (matching != nullptr) {
2196     const char* p;
2197     int ar;
2198
2199     while ((ar = archive_match_path_unmatched_inclusions_next(matching, &p)) ==
2200            ARCHIVE_OK) {
2201       cmSystemTools::Error("tar: " + std::string(p) +
2202                            ": Not found in archive");
2203       error_occured = true;
2204     }
2205     if (error_occured) {
2206       return false;
2207     }
2208     if (ar == ARCHIVE_FATAL) {
2209       cmSystemTools::Error("tar: Out of memory");
2210       return false;
2211     }
2212   }
2213   archive_match_free(matching);
2214   archive_write_free(ext);
2215   archive_read_close(a);
2216   archive_read_free(a);
2217   return r == ARCHIVE_EOF || r == ARCHIVE_OK;
2218 }
2219 }
2220 #endif
2221
2222 bool cmSystemTools::ExtractTar(const std::string& outFileName,
2223                                const std::vector<std::string>& files,
2224                                cmTarExtractTimestamps extractTimestamps,
2225                                bool verbose)
2226 {
2227 #if !defined(CMAKE_BOOTSTRAP)
2228   return extract_tar(outFileName, files, verbose, extractTimestamps, true);
2229 #else
2230   (void)outFileName;
2231   (void)files;
2232   (void)extractTimestamps;
2233   (void)verbose;
2234   return false;
2235 #endif
2236 }
2237
2238 bool cmSystemTools::ListTar(const std::string& outFileName,
2239                             const std::vector<std::string>& files,
2240                             bool verbose)
2241 {
2242 #if !defined(CMAKE_BOOTSTRAP)
2243   return extract_tar(outFileName, files, verbose, cmTarExtractTimestamps::Yes,
2244                      false);
2245 #else
2246   (void)outFileName;
2247   (void)files;
2248   (void)verbose;
2249   return false;
2250 #endif
2251 }
2252
2253 int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
2254                                cmDuration timeout, std::vector<char>& out,
2255                                std::vector<char>& err)
2256 {
2257   line.clear();
2258   auto outiter = out.begin();
2259   auto erriter = err.begin();
2260   cmProcessOutput processOutput;
2261   std::string strdata;
2262   while (true) {
2263     // Check for a newline in stdout.
2264     for (; outiter != out.end(); ++outiter) {
2265       if ((*outiter == '\r') && ((outiter + 1) == out.end())) {
2266         break;
2267       }
2268       if (*outiter == '\n' || *outiter == '\0') {
2269         std::vector<char>::size_type length = outiter - out.begin();
2270         if (length > 1 && *(outiter - 1) == '\r') {
2271           --length;
2272         }
2273         if (length > 0) {
2274           line.append(out.data(), length);
2275         }
2276         out.erase(out.begin(), outiter + 1);
2277         return cmsysProcess_Pipe_STDOUT;
2278       }
2279     }
2280
2281     // Check for a newline in stderr.
2282     for (; erriter != err.end(); ++erriter) {
2283       if ((*erriter == '\r') && ((erriter + 1) == err.end())) {
2284         break;
2285       }
2286       if (*erriter == '\n' || *erriter == '\0') {
2287         std::vector<char>::size_type length = erriter - err.begin();
2288         if (length > 1 && *(erriter - 1) == '\r') {
2289           --length;
2290         }
2291         if (length > 0) {
2292           line.append(err.data(), length);
2293         }
2294         err.erase(err.begin(), erriter + 1);
2295         return cmsysProcess_Pipe_STDERR;
2296       }
2297     }
2298
2299     // No newlines found.  Wait for more data from the process.
2300     int length;
2301     char* data;
2302     double timeoutAsDbl = timeout.count();
2303     int pipe =
2304       cmsysProcess_WaitForData(process, &data, &length, &timeoutAsDbl);
2305     if (pipe == cmsysProcess_Pipe_Timeout) {
2306       // Timeout has been exceeded.
2307       return pipe;
2308     }
2309     if (pipe == cmsysProcess_Pipe_STDOUT) {
2310       processOutput.DecodeText(data, length, strdata, 1);
2311       // Append to the stdout buffer.
2312       std::vector<char>::size_type size = out.size();
2313       cm::append(out, strdata);
2314       outiter = out.begin() + size;
2315     } else if (pipe == cmsysProcess_Pipe_STDERR) {
2316       processOutput.DecodeText(data, length, strdata, 2);
2317       // Append to the stderr buffer.
2318       std::vector<char>::size_type size = err.size();
2319       cm::append(err, strdata);
2320       erriter = err.begin() + size;
2321     } else if (pipe == cmsysProcess_Pipe_None) {
2322       // Both stdout and stderr pipes have broken.  Return leftover data.
2323       processOutput.DecodeText(std::string(), strdata, 1);
2324       if (!strdata.empty()) {
2325         std::vector<char>::size_type size = out.size();
2326         cm::append(out, strdata);
2327         outiter = out.begin() + size;
2328       }
2329       processOutput.DecodeText(std::string(), strdata, 2);
2330       if (!strdata.empty()) {
2331         std::vector<char>::size_type size = err.size();
2332         cm::append(err, strdata);
2333         erriter = err.begin() + size;
2334       }
2335       if (!out.empty()) {
2336         line.append(out.data(), outiter - out.begin());
2337         out.erase(out.begin(), out.end());
2338         return cmsysProcess_Pipe_STDOUT;
2339       }
2340       if (!err.empty()) {
2341         line.append(err.data(), erriter - err.begin());
2342         err.erase(err.begin(), err.end());
2343         return cmsysProcess_Pipe_STDERR;
2344       }
2345       return cmsysProcess_Pipe_None;
2346     }
2347   }
2348 }
2349
2350 #ifdef _WIN32
2351 static void EnsureStdPipe(DWORD fd)
2352 {
2353   if (GetStdHandle(fd) != INVALID_HANDLE_VALUE) {
2354     return;
2355   }
2356   SECURITY_ATTRIBUTES sa;
2357   sa.nLength = sizeof(sa);
2358   sa.lpSecurityDescriptor = NULL;
2359   sa.bInheritHandle = TRUE;
2360
2361   HANDLE h = CreateFileW(
2362     L"NUL",
2363     fd == STD_INPUT_HANDLE ? FILE_GENERIC_READ
2364                            : FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES,
2365     FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, NULL);
2366
2367   if (h == INVALID_HANDLE_VALUE) {
2368     LPSTR message = NULL;
2369     DWORD size = FormatMessageA(
2370       FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
2371         FORMAT_MESSAGE_IGNORE_INSERTS,
2372       NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2373       (LPSTR)&message, 0, NULL);
2374     std::string msg = std::string(message, size);
2375     LocalFree(message);
2376     std::cerr << "failed to open NUL for missing stdio pipe: " << msg;
2377     abort();
2378   }
2379
2380   SetStdHandle(fd, h);
2381 }
2382
2383 void cmSystemTools::EnsureStdPipes()
2384 {
2385   EnsureStdPipe(STD_INPUT_HANDLE);
2386   EnsureStdPipe(STD_OUTPUT_HANDLE);
2387   EnsureStdPipe(STD_ERROR_HANDLE);
2388 }
2389 #else
2390 static void EnsureStdPipe(int fd)
2391 {
2392   if (fcntl(fd, F_GETFD) != -1 || errno != EBADF) {
2393     return;
2394   }
2395
2396   int f = open("/dev/null", fd == STDIN_FILENO ? O_RDONLY : O_WRONLY);
2397   if (f == -1) {
2398     perror("failed to open /dev/null for missing stdio pipe");
2399     abort();
2400   }
2401   if (f != fd) {
2402     dup2(f, fd);
2403     close(f);
2404   }
2405 }
2406
2407 void cmSystemTools::EnsureStdPipes()
2408 {
2409   EnsureStdPipe(STDIN_FILENO);
2410   EnsureStdPipe(STDOUT_FILENO);
2411   EnsureStdPipe(STDERR_FILENO);
2412 }
2413 #endif
2414
2415 void cmSystemTools::DoNotInheritStdPipes()
2416 {
2417 #ifdef _WIN32
2418   // Check to see if we are attached to a console
2419   // if so, then do not stop the inherited pipes
2420   // or stdout and stderr will not show up in dos
2421   // shell windows
2422   CONSOLE_SCREEN_BUFFER_INFO hOutInfo;
2423   HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
2424   if (GetConsoleScreenBufferInfo(hOut, &hOutInfo)) {
2425     return;
2426   }
2427   {
2428     HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
2429     DuplicateHandle(GetCurrentProcess(), out, GetCurrentProcess(), &out, 0,
2430                     FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2431     SetStdHandle(STD_OUTPUT_HANDLE, out);
2432   }
2433   {
2434     HANDLE out = GetStdHandle(STD_ERROR_HANDLE);
2435     DuplicateHandle(GetCurrentProcess(), out, GetCurrentProcess(), &out, 0,
2436                     FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2437     SetStdHandle(STD_ERROR_HANDLE, out);
2438   }
2439 #endif
2440 }
2441
2442 #ifdef _WIN32
2443 #  ifndef CRYPT_SILENT
2444 #    define CRYPT_SILENT 0x40 /* Not defined by VS 6 version of header.  */
2445 #  endif
2446 static int WinCryptRandom(void* data, size_t size)
2447 {
2448   int result = 0;
2449   HCRYPTPROV hProvider = 0;
2450   if (CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL,
2451                            CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
2452     result = CryptGenRandom(hProvider, (DWORD)size, (BYTE*)data) ? 1 : 0;
2453     CryptReleaseContext(hProvider, 0);
2454   }
2455   return result;
2456 }
2457 #endif
2458
2459 unsigned int cmSystemTools::RandomSeed()
2460 {
2461 #if defined(_WIN32) && !defined(__CYGWIN__)
2462   unsigned int seed = 0;
2463
2464   // Try using a real random source.
2465   if (WinCryptRandom(&seed, sizeof(seed))) {
2466     return seed;
2467   }
2468
2469   // Fall back to the time and pid.
2470   FILETIME ft;
2471   GetSystemTimeAsFileTime(&ft);
2472   unsigned int t1 = static_cast<unsigned int>(ft.dwHighDateTime);
2473   unsigned int t2 = static_cast<unsigned int>(ft.dwLowDateTime);
2474   unsigned int pid = static_cast<unsigned int>(GetCurrentProcessId());
2475   return t1 ^ t2 ^ pid;
2476 #else
2477   union
2478   {
2479     unsigned int integer;
2480     char bytes[sizeof(unsigned int)];
2481   } seed;
2482
2483   // Try using a real random source.
2484   cmsys::ifstream fin;
2485   fin.rdbuf()->pubsetbuf(nullptr, 0); // Unbuffered read.
2486   fin.open("/dev/urandom");
2487   if (fin.good() && fin.read(seed.bytes, sizeof(seed)) &&
2488       fin.gcount() == sizeof(seed)) {
2489     return seed.integer;
2490   }
2491
2492   // Fall back to the time and pid.
2493   struct timeval t;
2494   gettimeofday(&t, nullptr);
2495   unsigned int pid = static_cast<unsigned int>(getpid());
2496   unsigned int tv_sec = static_cast<unsigned int>(t.tv_sec);
2497   unsigned int tv_usec = static_cast<unsigned int>(t.tv_usec);
2498   // Since tv_usec never fills more than 11 bits we shift it to fill
2499   // in the slow-changing high-order bits of tv_sec.
2500   return tv_sec ^ (tv_usec << 21) ^ pid;
2501 #endif
2502 }
2503
2504 static std::string cmSystemToolsCMakeCommand;
2505 static std::string cmSystemToolsCTestCommand;
2506 static std::string cmSystemToolsCPackCommand;
2507 static std::string cmSystemToolsCMakeCursesCommand;
2508 static std::string cmSystemToolsCMakeGUICommand;
2509 static std::string cmSystemToolsCMClDepsCommand;
2510 static std::string cmSystemToolsCMakeRoot;
2511 static std::string cmSystemToolsHTMLDoc;
2512 void cmSystemTools::FindCMakeResources(const char* argv0)
2513 {
2514   std::string exe_dir;
2515 #if defined(_WIN32) && !defined(__CYGWIN__)
2516   (void)argv0; // ignore this on windows
2517   wchar_t modulepath[_MAX_PATH];
2518   ::GetModuleFileNameW(NULL, modulepath, sizeof(modulepath));
2519   std::string path = cmsys::Encoding::ToNarrow(modulepath);
2520   std::string realPath =
2521     cmSystemTools::GetRealPathResolvingWindowsSubst(path, NULL);
2522   if (realPath.empty()) {
2523     realPath = path;
2524   }
2525   exe_dir = cmSystemTools::GetFilenamePath(realPath);
2526 #elif defined(__APPLE__)
2527   (void)argv0; // ignore this on OS X
2528 #  define CM_EXE_PATH_LOCAL_SIZE 16384
2529   char exe_path_local[CM_EXE_PATH_LOCAL_SIZE];
2530 #  if defined(MAC_OS_X_VERSION_10_3) && !defined(MAC_OS_X_VERSION_10_4)
2531   unsigned long exe_path_size = CM_EXE_PATH_LOCAL_SIZE;
2532 #  else
2533   uint32_t exe_path_size = CM_EXE_PATH_LOCAL_SIZE;
2534 #  endif
2535 #  undef CM_EXE_PATH_LOCAL_SIZE
2536   char* exe_path = exe_path_local;
2537   if (_NSGetExecutablePath(exe_path, &exe_path_size) < 0) {
2538     exe_path = static_cast<char*>(malloc(exe_path_size));
2539     _NSGetExecutablePath(exe_path, &exe_path_size);
2540   }
2541   exe_dir =
2542     cmSystemTools::GetFilenamePath(cmSystemTools::GetRealPath(exe_path));
2543   if (exe_path != exe_path_local) {
2544     free(exe_path);
2545   }
2546   if (cmSystemTools::GetFilenameName(exe_dir) == "MacOS") {
2547     // The executable is inside an application bundle.
2548     // Look for ..<CMAKE_BIN_DIR> (install tree) and then fall back to
2549     // ../../../bin (build tree).
2550     exe_dir = cmSystemTools::GetFilenamePath(exe_dir);
2551     if (cmSystemTools::FileExists(exe_dir + CMAKE_BIN_DIR "/cmake")) {
2552       exe_dir += CMAKE_BIN_DIR;
2553     } else {
2554       exe_dir = cmSystemTools::GetFilenamePath(exe_dir);
2555       exe_dir = cmSystemTools::GetFilenamePath(exe_dir);
2556     }
2557   }
2558 #else
2559   std::string errorMsg;
2560   std::string exe;
2561   if (cmSystemTools::FindProgramPath(argv0, exe, errorMsg)) {
2562     // remove symlinks
2563     exe = cmSystemTools::GetRealPath(exe);
2564     exe_dir = cmSystemTools::GetFilenamePath(exe);
2565   } else {
2566     // ???
2567   }
2568 #endif
2569   exe_dir = cmSystemTools::GetActualCaseForPath(exe_dir);
2570   cmSystemToolsCMakeCommand =
2571     cmStrCat(exe_dir, "/cmake", cmSystemTools::GetExecutableExtension());
2572 #ifdef CMAKE_BOOTSTRAP
2573   // The bootstrap cmake does not provide the other tools,
2574   // so use the directory where they are about to be built.
2575   exe_dir = CMAKE_BOOTSTRAP_BINARY_DIR "/bin";
2576 #endif
2577   cmSystemToolsCTestCommand =
2578     cmStrCat(exe_dir, "/ctest", cmSystemTools::GetExecutableExtension());
2579   cmSystemToolsCPackCommand =
2580     cmStrCat(exe_dir, "/cpack", cmSystemTools::GetExecutableExtension());
2581   cmSystemToolsCMakeGUICommand =
2582     cmStrCat(exe_dir, "/cmake-gui", cmSystemTools::GetExecutableExtension());
2583   if (!cmSystemTools::FileExists(cmSystemToolsCMakeGUICommand)) {
2584     cmSystemToolsCMakeGUICommand.clear();
2585   }
2586   cmSystemToolsCMakeCursesCommand =
2587     cmStrCat(exe_dir, "/ccmake", cmSystemTools::GetExecutableExtension());
2588   if (!cmSystemTools::FileExists(cmSystemToolsCMakeCursesCommand)) {
2589     cmSystemToolsCMakeCursesCommand.clear();
2590   }
2591   cmSystemToolsCMClDepsCommand =
2592     cmStrCat(exe_dir, "/cmcldeps", cmSystemTools::GetExecutableExtension());
2593   if (!cmSystemTools::FileExists(cmSystemToolsCMClDepsCommand)) {
2594     cmSystemToolsCMClDepsCommand.clear();
2595   }
2596
2597 #ifndef CMAKE_BOOTSTRAP
2598   // Install tree has
2599   // - "<prefix><CMAKE_BIN_DIR>/cmake"
2600   // - "<prefix><CMAKE_DATA_DIR>"
2601   // - "<prefix><CMAKE_DOC_DIR>"
2602   if (cmHasLiteralSuffix(exe_dir, CMAKE_BIN_DIR)) {
2603     std::string const prefix =
2604       exe_dir.substr(0, exe_dir.size() - cmStrLen(CMAKE_BIN_DIR));
2605     cmSystemToolsCMakeRoot = cmStrCat(prefix, CMAKE_DATA_DIR);
2606     if (cmSystemTools::FileExists(
2607           cmStrCat(prefix, CMAKE_DOC_DIR "/html/index.html"))) {
2608       cmSystemToolsHTMLDoc = cmStrCat(prefix, CMAKE_DOC_DIR "/html");
2609     }
2610   }
2611   if (cmSystemToolsCMakeRoot.empty() ||
2612       !cmSystemTools::FileExists(
2613         cmStrCat(cmSystemToolsCMakeRoot, "/Modules/CMake.cmake"))) {
2614     // Build tree has "<build>/bin[/<config>]/cmake" and
2615     // "<build>/CMakeFiles/CMakeSourceDir.txt".
2616     std::string dir = cmSystemTools::GetFilenamePath(exe_dir);
2617     std::string src_dir_txt = cmStrCat(dir, "/CMakeFiles/CMakeSourceDir.txt");
2618     cmsys::ifstream fin(src_dir_txt.c_str());
2619     std::string src_dir;
2620     if (fin && cmSystemTools::GetLineFromStream(fin, src_dir) &&
2621         cmSystemTools::FileIsDirectory(src_dir)) {
2622       cmSystemToolsCMakeRoot = src_dir;
2623     } else {
2624       dir = cmSystemTools::GetFilenamePath(dir);
2625       src_dir_txt = cmStrCat(dir, "/CMakeFiles/CMakeSourceDir.txt");
2626       cmsys::ifstream fin2(src_dir_txt.c_str());
2627       if (fin2 && cmSystemTools::GetLineFromStream(fin2, src_dir) &&
2628           cmSystemTools::FileIsDirectory(src_dir)) {
2629         cmSystemToolsCMakeRoot = src_dir;
2630       }
2631     }
2632     if (!cmSystemToolsCMakeRoot.empty() && cmSystemToolsHTMLDoc.empty() &&
2633         cmSystemTools::FileExists(
2634           cmStrCat(dir, "/Utilities/Sphinx/html/index.html"))) {
2635       cmSystemToolsHTMLDoc = cmStrCat(dir, "/Utilities/Sphinx/html");
2636     }
2637   }
2638 #else
2639   // Bootstrap build knows its source.
2640   cmSystemToolsCMakeRoot = CMAKE_BOOTSTRAP_SOURCE_DIR;
2641 #endif
2642 }
2643
2644 std::string const& cmSystemTools::GetCMakeCommand()
2645 {
2646   return cmSystemToolsCMakeCommand;
2647 }
2648
2649 std::string const& cmSystemTools::GetCTestCommand()
2650 {
2651   return cmSystemToolsCTestCommand;
2652 }
2653
2654 std::string const& cmSystemTools::GetCPackCommand()
2655 {
2656   return cmSystemToolsCPackCommand;
2657 }
2658
2659 std::string const& cmSystemTools::GetCMakeCursesCommand()
2660 {
2661   return cmSystemToolsCMakeCursesCommand;
2662 }
2663
2664 std::string const& cmSystemTools::GetCMakeGUICommand()
2665 {
2666   return cmSystemToolsCMakeGUICommand;
2667 }
2668
2669 std::string const& cmSystemTools::GetCMClDepsCommand()
2670 {
2671   return cmSystemToolsCMClDepsCommand;
2672 }
2673
2674 std::string const& cmSystemTools::GetCMakeRoot()
2675 {
2676   return cmSystemToolsCMakeRoot;
2677 }
2678
2679 std::string const& cmSystemTools::GetHTMLDoc()
2680 {
2681   return cmSystemToolsHTMLDoc;
2682 }
2683
2684 std::string cmSystemTools::GetCurrentWorkingDirectory()
2685 {
2686   return cmSystemTools::CollapseFullPath(
2687     cmsys::SystemTools::GetCurrentWorkingDirectory());
2688 }
2689
2690 void cmSystemTools::MakefileColorEcho(int color, const char* message,
2691                                       bool newline, bool enabled)
2692 {
2693   // On some platforms (an MSYS prompt) cmsysTerminal may not be able
2694   // to determine whether the stream is displayed on a tty.  In this
2695   // case it assumes no unless we tell it otherwise.  Since we want
2696   // color messages to be displayed for users we will assume yes.
2697   // However, we can test for some situations when the answer is most
2698   // likely no.
2699   int assumeTTY = cmsysTerminal_Color_AssumeTTY;
2700   if (cmSystemTools::HasEnv("DART_TEST_FROM_DART") ||
2701       cmSystemTools::HasEnv("DASHBOARD_TEST_FROM_CTEST") ||
2702       cmSystemTools::HasEnv("CTEST_INTERACTIVE_DEBUG_MODE")) {
2703     // Avoid printing color escapes during dashboard builds.
2704     assumeTTY = 0;
2705   }
2706
2707   if (enabled && color != cmsysTerminal_Color_Normal) {
2708     // Print with color.  Delay the newline until later so that
2709     // all color restore sequences appear before it.
2710     cmsysTerminal_cfprintf(color | assumeTTY, stdout, "%s", message);
2711   } else {
2712     // Color is disabled.  Print without color.
2713     fprintf(stdout, "%s", message);
2714   }
2715
2716   if (newline) {
2717     fprintf(stdout, "\n");
2718   }
2719 }
2720
2721 bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath,
2722                                        std::string& soname)
2723 {
2724   // For ELF shared libraries use a real parser to get the correct
2725   // soname.
2726   cmELF elf(fullPath.c_str());
2727   if (elf) {
2728     return elf.GetSOName(soname);
2729   }
2730
2731   // If the file is not a symlink we have no guess for its soname.
2732   if (!cmSystemTools::FileIsSymlink(fullPath)) {
2733     return false;
2734   }
2735   if (!cmSystemTools::ReadSymlink(fullPath, soname)) {
2736     return false;
2737   }
2738
2739   // If the symlink has a path component we have no guess for the soname.
2740   if (!cmSystemTools::GetFilenamePath(soname).empty()) {
2741     return false;
2742   }
2743
2744   // If the symlink points at an extended version of the same name
2745   // assume it is the soname.
2746   std::string name = cmSystemTools::GetFilenameName(fullPath);
2747   return soname.length() > name.length() &&
2748     soname.compare(0, name.length(), name) == 0;
2749 }
2750
2751 bool cmSystemTools::GuessLibraryInstallName(std::string const& fullPath,
2752                                             std::string& soname)
2753 {
2754 #if defined(CMake_USE_MACH_PARSER)
2755   cmMachO macho(fullPath.c_str());
2756   if (macho) {
2757     return macho.GetInstallName(soname);
2758   }
2759 #else
2760   (void)fullPath;
2761   (void)soname;
2762 #endif
2763
2764   return false;
2765 }
2766
2767 static std::string::size_type cmSystemToolsFindRPath(
2768   cm::string_view const& have, cm::string_view const& want)
2769 {
2770   std::string::size_type pos = 0;
2771   while (pos < have.size()) {
2772     // Look for an occurrence of the string.
2773     std::string::size_type const beg = have.find(want, pos);
2774     if (beg == std::string::npos) {
2775       return std::string::npos;
2776     }
2777
2778     // Make sure it is separated from preceding entries.
2779     if (beg > 0 && have[beg - 1] != ':') {
2780       pos = beg + 1;
2781       continue;
2782     }
2783
2784     // Make sure it is separated from following entries.
2785     std::string::size_type const end = beg + want.size();
2786     if (end < have.size() && have[end] != ':') {
2787       pos = beg + 1;
2788       continue;
2789     }
2790
2791     // Return the position of the path portion.
2792     return beg;
2793   }
2794
2795   // The desired rpath was not found.
2796   return std::string::npos;
2797 }
2798
2799 namespace {
2800 struct cmSystemToolsRPathInfo
2801 {
2802   unsigned long Position;
2803   unsigned long Size;
2804   std::string Name;
2805   std::string Value;
2806 };
2807
2808 using EmptyCallback = std::function<bool(std::string*, const cmELF&)>;
2809 using AdjustCallback = std::function<bool(
2810   cm::optional<std::string>&, const std::string&, const char*, std::string*)>;
2811
2812 cm::optional<bool> AdjustRPathELF(std::string const& file,
2813                                   const EmptyCallback& emptyCallback,
2814                                   const AdjustCallback& adjustCallback,
2815                                   std::string* emsg, bool* changed)
2816 {
2817   if (changed) {
2818     *changed = false;
2819   }
2820   int rp_count = 0;
2821   bool remove_rpath = true;
2822   cmSystemToolsRPathInfo rp[2];
2823   {
2824     // Parse the ELF binary.
2825     cmELF elf(file.c_str());
2826     if (!elf) {
2827       return cm::nullopt; // Not a valid ELF file.
2828     }
2829
2830     // Get the RPATH and RUNPATH entries from it.
2831     int se_count = 0;
2832     cmELF::StringEntry const* se[2] = { nullptr, nullptr };
2833     const char* se_name[2] = { nullptr, nullptr };
2834     if (cmELF::StringEntry const* se_rpath = elf.GetRPath()) {
2835       se[se_count] = se_rpath;
2836       se_name[se_count] = "RPATH";
2837       ++se_count;
2838     }
2839     if (cmELF::StringEntry const* se_runpath = elf.GetRunPath()) {
2840       se[se_count] = se_runpath;
2841       se_name[se_count] = "RUNPATH";
2842       ++se_count;
2843     }
2844     if (se_count == 0) {
2845       return emptyCallback(emsg, elf);
2846     }
2847
2848     for (int i = 0; i < se_count; ++i) {
2849       // If both RPATH and RUNPATH refer to the same string literal it
2850       // needs to be changed only once.
2851       if (rp_count && rp[0].Position == se[i]->Position) {
2852         continue;
2853       }
2854
2855       // Store information about the entry in the file.
2856       rp[rp_count].Position = se[i]->Position;
2857       rp[rp_count].Size = se[i]->Size;
2858       rp[rp_count].Name = se_name[i];
2859
2860       // Adjust the rpath.
2861       cm::optional<std::string> outRPath;
2862       if (!adjustCallback(outRPath, se[i]->Value, se_name[i], emsg)) {
2863         return false;
2864       }
2865
2866       if (outRPath) {
2867         if (!outRPath->empty()) {
2868           remove_rpath = false;
2869         }
2870
2871         // Make sure there is enough room to store the new rpath and at
2872         // least one null terminator.
2873         if (rp[rp_count].Size < outRPath->length() + 1) {
2874           if (emsg) {
2875             *emsg = cmStrCat("The replacement path is too long for the ",
2876                              se_name[i], " entry.");
2877           }
2878           return false;
2879         }
2880
2881         // This entry is ready for update.
2882         rp[rp_count].Value = std::move(*outRPath);
2883         ++rp_count;
2884       } else {
2885         remove_rpath = false;
2886       }
2887     }
2888   }
2889
2890   // If no runtime path needs to be changed, we are done.
2891   if (rp_count == 0) {
2892     return true;
2893   }
2894
2895   // If the resulting rpath is empty, just remove the entire entry instead.
2896   if (remove_rpath) {
2897     return cmSystemTools::RemoveRPath(file, emsg, changed);
2898   }
2899
2900   {
2901     // Open the file for update.
2902     cmsys::ofstream f(file.c_str(),
2903                       std::ios::in | std::ios::out | std::ios::binary);
2904     if (!f) {
2905       if (emsg) {
2906         *emsg = "Error opening file for update.";
2907       }
2908       return false;
2909     }
2910
2911     // Store the new RPATH and RUNPATH strings.
2912     for (int i = 0; i < rp_count; ++i) {
2913       // Seek to the RPATH position.
2914       if (!f.seekp(rp[i].Position)) {
2915         if (emsg) {
2916           *emsg = cmStrCat("Error seeking to ", rp[i].Name, " position.");
2917         }
2918         return false;
2919       }
2920
2921       // Write the new rpath.  Follow it with enough null terminators to
2922       // fill the string table entry.
2923       f << rp[i].Value;
2924       for (unsigned long j = rp[i].Value.length(); j < rp[i].Size; ++j) {
2925         f << '\0';
2926       }
2927
2928       // Make sure it wrote correctly.
2929       if (!f) {
2930         if (emsg) {
2931           *emsg = cmStrCat("Error writing the new ", rp[i].Name,
2932                            " string to the file.");
2933         }
2934         return false;
2935       }
2936     }
2937   }
2938
2939   // Everything was updated successfully.
2940   if (changed) {
2941     *changed = true;
2942   }
2943   return true;
2944 }
2945
2946 std::function<bool(std::string*, const cmELF&)> MakeEmptyCallback(
2947   const std::string& newRPath)
2948 {
2949   return [newRPath](std::string* emsg, const cmELF& elf) -> bool {
2950     if (newRPath.empty()) {
2951       // The new rpath is empty and there is no rpath anyway so it is
2952       // okay.
2953       return true;
2954     }
2955     if (emsg) {
2956       *emsg =
2957         cmStrCat("No valid ELF RPATH or RUNPATH entry exists in the file; ",
2958                  elf.GetErrorMessage());
2959     }
2960     return false;
2961   };
2962 }
2963 }
2964
2965 static cm::optional<bool> ChangeRPathELF(std::string const& file,
2966                                          std::string const& oldRPath,
2967                                          std::string const& newRPath,
2968                                          bool removeEnvironmentRPath,
2969                                          std::string* emsg, bool* changed)
2970 {
2971   auto adjustCallback = [oldRPath, newRPath, removeEnvironmentRPath](
2972                           cm::optional<std::string>& outRPath,
2973                           const std::string& inRPath, const char* se_name,
2974                           std::string* emsg2) -> bool {
2975     // Make sure the current rpath contains the old rpath.
2976     std::string::size_type pos = cmSystemToolsFindRPath(inRPath, oldRPath);
2977     if (pos == std::string::npos) {
2978       // If it contains the new rpath instead then it is okay.
2979       if (cmSystemToolsFindRPath(inRPath, newRPath) != std::string::npos) {
2980         return true;
2981       }
2982       if (emsg2) {
2983         std::ostringstream e;
2984         /* clang-format off */
2985         e << "The current " << se_name << " is:\n"
2986           << "  " << inRPath << "\n"
2987           << "which does not contain:\n"
2988           << "  " << oldRPath << "\n"
2989           << "as was expected.";
2990         /* clang-format on */
2991         *emsg2 = e.str();
2992       }
2993       return false;
2994     }
2995
2996     std::string::size_type prefix_len = pos;
2997
2998     // If oldRPath was at the end of the file's RPath, and newRPath is empty,
2999     // we should remove the unnecessary ':' at the end.
3000     if (newRPath.empty() && pos > 0 && inRPath[pos - 1] == ':' &&
3001         pos + oldRPath.length() == inRPath.length()) {
3002       prefix_len--;
3003     }
3004
3005     // Construct the new value which preserves the part of the path
3006     // not being changed.
3007     outRPath.emplace();
3008     if (!removeEnvironmentRPath) {
3009       *outRPath += inRPath.substr(0, prefix_len);
3010     }
3011     *outRPath += newRPath;
3012     *outRPath += inRPath.substr(pos + oldRPath.length());
3013
3014     return true;
3015   };
3016
3017   return AdjustRPathELF(file, MakeEmptyCallback(newRPath), adjustCallback,
3018                         emsg, changed);
3019 }
3020
3021 static cm::optional<bool> SetRPathELF(std::string const& file,
3022                                       std::string const& newRPath,
3023                                       std::string* emsg, bool* changed)
3024 {
3025   auto adjustCallback = [newRPath](cm::optional<std::string>& outRPath,
3026                                    const std::string& inRPath,
3027                                    const char* /*se_name*/, std::string *
3028                                    /*emsg*/) -> bool {
3029     if (inRPath != newRPath) {
3030       outRPath = newRPath;
3031     }
3032     return true;
3033   };
3034
3035   return AdjustRPathELF(file, MakeEmptyCallback(newRPath), adjustCallback,
3036                         emsg, changed);
3037 }
3038 static cm::optional<bool> ChangeRPathXCOFF(std::string const& file,
3039                                            std::string const& oldRPath,
3040                                            std::string const& newRPath,
3041                                            bool removeEnvironmentRPath,
3042                                            std::string* emsg, bool* changed)
3043 {
3044   if (changed) {
3045     *changed = false;
3046   }
3047 #if !defined(CMake_USE_XCOFF_PARSER)
3048   (void)file;
3049   (void)oldRPath;
3050   (void)newRPath;
3051   (void)removeEnvironmentRPath;
3052   (void)emsg;
3053   return cm::nullopt;
3054 #else
3055   bool chg = false;
3056   cmXCOFF xcoff(file.c_str(), cmXCOFF::Mode::ReadWrite);
3057   if (!xcoff) {
3058     return cm::nullopt; // Not a valid XCOFF file
3059   }
3060   if (cm::optional<cm::string_view> maybeLibPath = xcoff.GetLibPath()) {
3061     cm::string_view libPath = *maybeLibPath;
3062     // Make sure the current rpath contains the old rpath.
3063     std::string::size_type pos = cmSystemToolsFindRPath(libPath, oldRPath);
3064     if (pos == std::string::npos) {
3065       // If it contains the new rpath instead then it is okay.
3066       if (cmSystemToolsFindRPath(libPath, newRPath) != std::string::npos) {
3067         return true;
3068       }
3069       if (emsg) {
3070         std::ostringstream e;
3071         /* clang-format off */
3072         e << "The current RPATH is:\n"
3073           << "  " << libPath << "\n"
3074           << "which does not contain:\n"
3075           << "  " << oldRPath << "\n"
3076           << "as was expected.";
3077         /* clang-format on */
3078         *emsg = e.str();
3079       }
3080       return false;
3081     }
3082
3083     // The prefix is either empty or ends in a ':'.
3084     cm::string_view prefix = libPath.substr(0, pos);
3085     if (newRPath.empty() && !prefix.empty()) {
3086       prefix.remove_suffix(1);
3087     }
3088
3089     // The suffix is either empty or starts in a ':'.
3090     cm::string_view suffix = libPath.substr(pos + oldRPath.length());
3091
3092     // Construct the new value which preserves the part of the path
3093     // not being changed.
3094     std::string newLibPath;
3095     if (!removeEnvironmentRPath) {
3096       newLibPath = std::string(prefix);
3097     }
3098     newLibPath += newRPath;
3099     newLibPath += suffix;
3100
3101     chg = xcoff.SetLibPath(newLibPath);
3102   }
3103   if (!xcoff) {
3104     if (emsg) {
3105       *emsg = xcoff.GetErrorMessage();
3106     }
3107     return false;
3108   }
3109
3110   // Everything was updated successfully.
3111   if (changed) {
3112     *changed = chg;
3113   }
3114   return true;
3115 #endif
3116 }
3117
3118 static cm::optional<bool> SetRPathXCOFF(std::string const& /*file*/,
3119                                         std::string const& /*newRPath*/,
3120                                         std::string* /*emsg*/,
3121                                         bool* /*changed*/)
3122 {
3123   return cm::nullopt; // Not implemented.
3124 }
3125
3126 bool cmSystemTools::ChangeRPath(std::string const& file,
3127                                 std::string const& oldRPath,
3128                                 std::string const& newRPath,
3129                                 bool removeEnvironmentRPath, std::string* emsg,
3130                                 bool* changed)
3131 {
3132   if (cm::optional<bool> result = ChangeRPathELF(
3133         file, oldRPath, newRPath, removeEnvironmentRPath, emsg, changed)) {
3134     return result.value();
3135   }
3136   if (cm::optional<bool> result = ChangeRPathXCOFF(
3137         file, oldRPath, newRPath, removeEnvironmentRPath, emsg, changed)) {
3138     return result.value();
3139   }
3140   // The file format is not recognized.  Assume it has no RPATH.
3141   if (newRPath.empty()) {
3142     // The caller wanted no RPATH anyway.
3143     return true;
3144   }
3145   if (emsg) {
3146     *emsg = "The file format is not recognized.";
3147   }
3148   return false;
3149 }
3150
3151 bool cmSystemTools::SetRPath(std::string const& file,
3152                              std::string const& newRPath, std::string* emsg,
3153                              bool* changed)
3154 {
3155   if (cm::optional<bool> result = SetRPathELF(file, newRPath, emsg, changed)) {
3156     return result.value();
3157   }
3158   if (cm::optional<bool> result =
3159         SetRPathXCOFF(file, newRPath, emsg, changed)) {
3160     return result.value();
3161   }
3162   // The file format is not recognized.  Assume it has no RPATH.
3163   if (newRPath.empty()) {
3164     // The caller wanted no RPATH anyway.
3165     return true;
3166   }
3167   if (emsg) {
3168     *emsg = "The file format is not recognized.";
3169   }
3170   return false;
3171 }
3172
3173 namespace {
3174 bool VersionCompare(cmSystemTools::CompareOp op, const char* lhss,
3175                     const char* rhss)
3176 {
3177   const char* endl = lhss;
3178   const char* endr = rhss;
3179   unsigned long lhs;
3180   unsigned long rhs;
3181
3182   while (((*endl >= '0') && (*endl <= '9')) ||
3183          ((*endr >= '0') && (*endr <= '9'))) {
3184     // Do component-wise comparison.
3185     lhs = strtoul(endl, const_cast<char**>(&endl), 10);
3186     rhs = strtoul(endr, const_cast<char**>(&endr), 10);
3187
3188     if (lhs < rhs) {
3189       // lhs < rhs, so true if operation is LESS
3190       return (op & cmSystemTools::OP_LESS) != 0;
3191     }
3192     if (lhs > rhs) {
3193       // lhs > rhs, so true if operation is GREATER
3194       return (op & cmSystemTools::OP_GREATER) != 0;
3195     }
3196
3197     if (*endr == '.') {
3198       endr++;
3199     }
3200
3201     if (*endl == '.') {
3202       endl++;
3203     }
3204   }
3205   // lhs == rhs, so true if operation is EQUAL
3206   return (op & cmSystemTools::OP_EQUAL) != 0;
3207 }
3208 }
3209
3210 bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op,
3211                                    const std::string& lhs,
3212                                    const std::string& rhs)
3213 {
3214   return ::VersionCompare(op, lhs.c_str(), rhs.c_str());
3215 }
3216 bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op,
3217                                    const std::string& lhs, const char rhs[])
3218 {
3219   return ::VersionCompare(op, lhs.c_str(), rhs);
3220 }
3221
3222 bool cmSystemTools::VersionCompareEqual(std::string const& lhs,
3223                                         std::string const& rhs)
3224 {
3225   return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, lhs, rhs);
3226 }
3227
3228 bool cmSystemTools::VersionCompareGreater(std::string const& lhs,
3229                                           std::string const& rhs)
3230 {
3231   return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, lhs, rhs);
3232 }
3233
3234 bool cmSystemTools::VersionCompareGreaterEq(std::string const& lhs,
3235                                             std::string const& rhs)
3236 {
3237   return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, lhs,
3238                                        rhs);
3239 }
3240
3241 static size_t cm_strverscmp_find_first_difference_or_end(const char* lhs,
3242                                                          const char* rhs)
3243 {
3244   size_t i = 0;
3245   /* Step forward until we find a difference or both strings end together.
3246      The difference may lie on the null-terminator of one string.  */
3247   while (lhs[i] == rhs[i] && lhs[i] != 0) {
3248     ++i;
3249   }
3250   return i;
3251 }
3252
3253 static size_t cm_strverscmp_find_digits_begin(const char* s, size_t i)
3254 {
3255   /* Step back until we are not preceded by a digit.  */
3256   while (i > 0 && isdigit(s[i - 1])) {
3257     --i;
3258   }
3259   return i;
3260 }
3261
3262 static size_t cm_strverscmp_find_digits_end(const char* s, size_t i)
3263 {
3264   /* Step forward over digits.  */
3265   while (isdigit(s[i])) {
3266     ++i;
3267   }
3268   return i;
3269 }
3270
3271 static size_t cm_strverscmp_count_leading_zeros(const char* s, size_t b)
3272 {
3273   size_t i = b;
3274   /* Step forward over zeros that are followed by another digit.  */
3275   while (s[i] == '0' && isdigit(s[i + 1])) {
3276     ++i;
3277   }
3278   return i - b;
3279 }
3280
3281 static int cm_strverscmp(const char* lhs, const char* rhs)
3282 {
3283   size_t const i = cm_strverscmp_find_first_difference_or_end(lhs, rhs);
3284   if (lhs[i] != rhs[i]) {
3285     /* The strings differ starting at 'i'.  Check for a digit sequence.  */
3286     size_t const b = cm_strverscmp_find_digits_begin(lhs, i);
3287     if (b != i || (isdigit(lhs[i]) && isdigit(rhs[i]))) {
3288       /* A digit sequence starts at 'b', preceding or at 'i'.  */
3289
3290       /* Look for leading zeros, implying a leading decimal point.  */
3291       size_t const lhs_zeros = cm_strverscmp_count_leading_zeros(lhs, b);
3292       size_t const rhs_zeros = cm_strverscmp_count_leading_zeros(rhs, b);
3293       if (lhs_zeros != rhs_zeros) {
3294         /* The side with more leading zeros orders first.  */
3295         return rhs_zeros > lhs_zeros ? 1 : -1;
3296       }
3297       if (lhs_zeros == 0) {
3298         /* No leading zeros; compare digit sequence lengths.  */
3299         size_t const lhs_end = cm_strverscmp_find_digits_end(lhs, i);
3300         size_t const rhs_end = cm_strverscmp_find_digits_end(rhs, i);
3301         if (lhs_end != rhs_end) {
3302           /* The side with fewer digits orders first.  */
3303           return lhs_end > rhs_end ? 1 : -1;
3304         }
3305       }
3306     }
3307   }
3308
3309   /* Ordering was not decided by digit sequence lengths; compare bytes.  */
3310   return lhs[i] - rhs[i];
3311 }
3312
3313 int cmSystemTools::strverscmp(std::string const& lhs, std::string const& rhs)
3314 {
3315   return cm_strverscmp(lhs.c_str(), rhs.c_str());
3316 }
3317
3318 static cm::optional<bool> RemoveRPathELF(std::string const& file,
3319                                          std::string* emsg, bool* removed)
3320 {
3321   if (removed) {
3322     *removed = false;
3323   }
3324   int zeroCount = 0;
3325   unsigned long zeroPosition[2] = { 0, 0 };
3326   unsigned long zeroSize[2] = { 0, 0 };
3327   unsigned long bytesBegin = 0;
3328   std::vector<char> bytes;
3329   {
3330     // Parse the ELF binary.
3331     cmELF elf(file.c_str());
3332     if (!elf) {
3333       return cm::nullopt; // Not a valid ELF file.
3334     }
3335
3336     // Get the RPATH and RUNPATH entries from it and sort them by index
3337     // in the dynamic section header.
3338     int se_count = 0;
3339     cmELF::StringEntry const* se[2] = { nullptr, nullptr };
3340     if (cmELF::StringEntry const* se_rpath = elf.GetRPath()) {
3341       se[se_count++] = se_rpath;
3342     }
3343     if (cmELF::StringEntry const* se_runpath = elf.GetRunPath()) {
3344       se[se_count++] = se_runpath;
3345     }
3346     if (se_count == 0) {
3347       // There is no RPATH or RUNPATH anyway.
3348       return true;
3349     }
3350     if (se_count == 2 && se[1]->IndexInSection < se[0]->IndexInSection) {
3351       std::swap(se[0], se[1]);
3352     }
3353
3354     // Obtain a copy of the dynamic entries
3355     cmELF::DynamicEntryList dentries = elf.GetDynamicEntries();
3356     if (dentries.empty()) {
3357       // This should happen only for invalid ELF files where a DT_NULL
3358       // appears before the end of the table.
3359       if (emsg) {
3360         *emsg = "DYNAMIC section contains a DT_NULL before the end.";
3361       }
3362       return false;
3363     }
3364
3365     // Save information about the string entries to be zeroed.
3366     zeroCount = se_count;
3367     for (int i = 0; i < se_count; ++i) {
3368       zeroPosition[i] = se[i]->Position;
3369       zeroSize[i] = se[i]->Size;
3370     }
3371
3372     // Get size of one DYNAMIC entry
3373     unsigned long const sizeof_dentry =
3374       elf.GetDynamicEntryPosition(1) - elf.GetDynamicEntryPosition(0);
3375
3376     // Adjust the entry list as necessary to remove the run path
3377     unsigned long entriesErased = 0;
3378     for (auto it = dentries.begin(); it != dentries.end();) {
3379       if (it->first == cmELF::TagRPath || it->first == cmELF::TagRunPath) {
3380         it = dentries.erase(it);
3381         entriesErased++;
3382         continue;
3383       }
3384       if (it->first == cmELF::TagMipsRldMapRel && elf.IsMIPS()) {
3385         // Background: debuggers need to know the "linker map" which contains
3386         // the addresses each dynamic object is loaded at. Most arches use
3387         // the DT_DEBUG tag which the dynamic linker writes to (directly) and
3388         // contain the location of the linker map, however on MIPS the
3389         // .dynamic section is always read-only so this is not possible. MIPS
3390         // objects instead contain a DT_MIPS_RLD_MAP tag which contains the
3391         // address where the dynamic linker will write to (an indirect
3392         // version of DT_DEBUG). Since this doesn't work when using PIE, a
3393         // relative equivalent was created - DT_MIPS_RLD_MAP_REL. Since this
3394         // version contains a relative offset, moving it changes the
3395         // calculated address. This may cause the dynamic linker to write
3396         // into memory it should not be changing.
3397         //
3398         // To fix this, we adjust the value of DT_MIPS_RLD_MAP_REL here. If
3399         // we move it up by n bytes, we add n bytes to the value of this tag.
3400         it->second += entriesErased * sizeof_dentry;
3401       }
3402
3403       it++;
3404     }
3405
3406     // Encode new entries list
3407     bytes = elf.EncodeDynamicEntries(dentries);
3408     bytesBegin = elf.GetDynamicEntryPosition(0);
3409   }
3410
3411   // Open the file for update.
3412   cmsys::ofstream f(file.c_str(),
3413                     std::ios::in | std::ios::out | std::ios::binary);
3414   if (!f) {
3415     if (emsg) {
3416       *emsg = "Error opening file for update.";
3417     }
3418     return false;
3419   }
3420
3421   // Write the new DYNAMIC table header.
3422   if (!f.seekp(bytesBegin)) {
3423     if (emsg) {
3424       *emsg = "Error seeking to DYNAMIC table header for RPATH.";
3425     }
3426     return false;
3427   }
3428   if (!f.write(bytes.data(), bytes.size())) {
3429     if (emsg) {
3430       *emsg = "Error replacing DYNAMIC table header.";
3431     }
3432     return false;
3433   }
3434
3435   // Fill the RPATH and RUNPATH strings with zero bytes.
3436   for (int i = 0; i < zeroCount; ++i) {
3437     if (!f.seekp(zeroPosition[i])) {
3438       if (emsg) {
3439         *emsg = "Error seeking to RPATH position.";
3440       }
3441       return false;
3442     }
3443     for (unsigned long j = 0; j < zeroSize[i]; ++j) {
3444       f << '\0';
3445     }
3446     if (!f) {
3447       if (emsg) {
3448         *emsg = "Error writing the empty rpath string to the file.";
3449       }
3450       return false;
3451     }
3452   }
3453
3454   // Everything was updated successfully.
3455   if (removed) {
3456     *removed = true;
3457   }
3458   return true;
3459 }
3460
3461 static cm::optional<bool> RemoveRPathXCOFF(std::string const& file,
3462                                            std::string* emsg, bool* removed)
3463 {
3464   if (removed) {
3465     *removed = false;
3466   }
3467 #if !defined(CMake_USE_XCOFF_PARSER)
3468   (void)file;
3469   (void)emsg;
3470   return cm::nullopt; // Cannot handle XCOFF files.
3471 #else
3472   cmXCOFF xcoff(file.c_str(), cmXCOFF::Mode::ReadWrite);
3473   if (!xcoff) {
3474     return cm::nullopt; // Not a valid XCOFF file.
3475   }
3476   bool rm = xcoff.RemoveLibPath();
3477   if (!xcoff) {
3478     if (emsg) {
3479       *emsg = xcoff.GetErrorMessage();
3480     }
3481     return false;
3482   }
3483
3484   if (removed) {
3485     *removed = rm;
3486   }
3487   return true;
3488 #endif
3489 }
3490 bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
3491                                 bool* removed)
3492 {
3493   if (cm::optional<bool> result = RemoveRPathELF(file, emsg, removed)) {
3494     return result.value();
3495   }
3496   if (cm::optional<bool> result = RemoveRPathXCOFF(file, emsg, removed)) {
3497     return result.value();
3498   }
3499   // The file format is not recognized.  Assume it has no RPATH.
3500   return true;
3501 }
3502
3503 bool cmSystemTools::CheckRPath(std::string const& file,
3504                                std::string const& newRPath)
3505 {
3506   // Parse the ELF binary.
3507   cmELF elf(file.c_str());
3508   if (elf) {
3509     // Get the RPATH or RUNPATH entry from it.
3510     cmELF::StringEntry const* se = elf.GetRPath();
3511     if (!se) {
3512       se = elf.GetRunPath();
3513     }
3514
3515     // Make sure the current rpath contains the new rpath.
3516     if (newRPath.empty()) {
3517       if (!se) {
3518         return true;
3519       }
3520     } else {
3521       if (se &&
3522           cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos) {
3523         return true;
3524       }
3525     }
3526     return false;
3527   }
3528 #if defined(CMake_USE_XCOFF_PARSER)
3529   // Parse the XCOFF binary.
3530   cmXCOFF xcoff(file.c_str());
3531   if (xcoff) {
3532     if (cm::optional<cm::string_view> libPath = xcoff.GetLibPath()) {
3533       if (cmSystemToolsFindRPath(*libPath, newRPath) != std::string::npos) {
3534         return true;
3535       }
3536     }
3537     return false;
3538   }
3539 #endif
3540   // The file format is not recognized.  Assume it has no RPATH.
3541   // Therefore we succeed if the new rpath is empty anyway.
3542   return newRPath.empty();
3543 }
3544
3545 bool cmSystemTools::RepeatedRemoveDirectory(const std::string& dir)
3546 {
3547 #ifdef _WIN32
3548   // Windows sometimes locks files temporarily so try a few times.
3549   WindowsFileRetry retry = cmSystemTools::GetWindowsFileRetry();
3550
3551   for (unsigned int i = 0; i < retry.Count; ++i) {
3552     if (cmSystemTools::RemoveADirectory(dir)) {
3553       return true;
3554     }
3555     cmSystemTools::Delay(retry.Delay);
3556   }
3557   return false;
3558 #else
3559   return static_cast<bool>(cmSystemTools::RemoveADirectory(dir));
3560 #endif
3561 }
3562
3563 std::string cmSystemTools::EncodeURL(std::string const& in, bool escapeSlashes)
3564 {
3565   std::string out;
3566   for (char c : in) {
3567     char hexCh[4] = { 0, 0, 0, 0 };
3568     hexCh[0] = c;
3569     switch (c) {
3570       case '+':
3571       case '?':
3572       case '\\':
3573       case '&':
3574       case ' ':
3575       case '=':
3576       case '%':
3577         snprintf(hexCh, sizeof(hexCh), "%%%02X", static_cast<int>(c));
3578         break;
3579       case '/':
3580         if (escapeSlashes) {
3581           strcpy(hexCh, "%2F");
3582         }
3583         break;
3584       default:
3585         break;
3586     }
3587     out.append(hexCh);
3588   }
3589   return out;
3590 }
3591
3592 cmsys::Status cmSystemTools::CreateSymlink(std::string const& origName,
3593                                            std::string const& newName)
3594 {
3595   cmsys::Status status =
3596     cmSystemTools::CreateSymlinkQuietly(origName, newName);
3597   if (!status) {
3598     cmSystemTools::Error(cmStrCat("failed to create symbolic link '", newName,
3599                                   "': ", status.GetString()));
3600   }
3601   return status;
3602 }
3603
3604 cmsys::Status cmSystemTools::CreateSymlinkQuietly(std::string const& origName,
3605                                                   std::string const& newName)
3606 {
3607   uv_fs_t req;
3608   int flags = 0;
3609 #if defined(_WIN32)
3610   if (cmsys::SystemTools::FileIsDirectory(origName)) {
3611     flags |= UV_FS_SYMLINK_DIR;
3612   }
3613 #endif
3614   int err = uv_fs_symlink(nullptr, &req, origName.c_str(), newName.c_str(),
3615                           flags, nullptr);
3616   cmsys::Status status;
3617   if (err) {
3618 #if defined(_WIN32)
3619     status = cmsys::Status::Windows(uv_fs_get_system_error(&req));
3620 #elif UV_VERSION_MAJOR > 1 || (UV_VERSION_MAJOR == 1 && UV_VERSION_MINOR >= 38)
3621     status = cmsys::Status::POSIX(uv_fs_get_system_error(&req));
3622 #else
3623     status = cmsys::Status::POSIX(-err);
3624 #endif
3625   }
3626   return status;
3627 }
3628
3629 cmsys::Status cmSystemTools::CreateLink(std::string const& origName,
3630                                         std::string const& newName)
3631 {
3632   cmsys::Status status = cmSystemTools::CreateLinkQuietly(origName, newName);
3633   if (!status) {
3634     cmSystemTools::Error(
3635       cmStrCat("failed to create link '", newName, "': ", status.GetString()));
3636   }
3637   return status;
3638 }
3639
3640 cmsys::Status cmSystemTools::CreateLinkQuietly(std::string const& origName,
3641                                                std::string const& newName)
3642 {
3643   uv_fs_t req;
3644   int err =
3645     uv_fs_link(nullptr, &req, origName.c_str(), newName.c_str(), nullptr);
3646   cmsys::Status status;
3647   if (err) {
3648 #if defined(_WIN32)
3649     status = cmsys::Status::Windows(uv_fs_get_system_error(&req));
3650 #elif UV_VERSION_MAJOR > 1 || (UV_VERSION_MAJOR == 1 && UV_VERSION_MINOR >= 38)
3651     status = cmsys::Status::POSIX(uv_fs_get_system_error(&req));
3652 #else
3653     status = cmsys::Status::POSIX(-err);
3654 #endif
3655   }
3656   return status;
3657 }
3658
3659 cm::string_view cmSystemTools::GetSystemName()
3660 {
3661 #if defined(_WIN32)
3662   return "Windows";
3663 #elif defined(__ANDROID__)
3664   return "Android";
3665 #else
3666   static struct utsname uts_name;
3667   static bool initialized = false;
3668   static cm::string_view systemName;
3669   if (initialized) {
3670     return systemName;
3671   }
3672   if (uname(&uts_name) >= 0) {
3673     initialized = true;
3674     systemName = uts_name.sysname;
3675
3676     if (cmIsOff(systemName)) {
3677       systemName = "UnknownOS";
3678     }
3679
3680     // fix for BSD/OS, remove the /
3681     static const cmsys::RegularExpression bsdOsRegex("BSD.OS");
3682     cmsys::RegularExpressionMatch match;
3683     if (bsdOsRegex.find(uts_name.sysname, match)) {
3684       systemName = "BSDOS";
3685     }
3686
3687     // fix for GNU/kFreeBSD, remove the GNU/
3688     if (systemName.find("kFreeBSD") != cm::string_view::npos) {
3689       systemName = "kFreeBSD";
3690     }
3691
3692     // fix for CYGWIN and MSYS which have windows version in them
3693     if (systemName.find("CYGWIN") != cm::string_view::npos) {
3694       systemName = "CYGWIN";
3695     }
3696
3697     if (systemName.find("MSYS") != cm::string_view::npos) {
3698       systemName = "MSYS";
3699     }
3700     return systemName;
3701   }
3702   return "";
3703 #endif
3704 }
3705
3706 char cmSystemTools::GetSystemPathlistSeparator()
3707 {
3708 #if defined(_WIN32)
3709   return ';';
3710 #else
3711   return ':';
3712 #endif
3713 }