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