cmSystemTools.cxx 75.6 KB
Newer Older
1
2
3
/*============================================================================
  CMake - Cross Platform Makefile Generator
  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4

5
6
  Distributed under the OSI-approved BSD License (the "License");
  see accompanying file Copyright.txt for details.
7

8
9
10
11
  This software is distributed WITHOUT ANY WARRANTY; without even the
  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the License for more information.
============================================================================*/
12
13
14
#if defined(_MSC_VER) && _MSC_VER < 1300
# define _WIN32_WINNT 0x0400 /* for wincrypt.h */
#endif
15
#include "cmSystemTools.h"
Ken Martin's avatar
Ken Martin committed
16
#include <ctype.h>
17
#include <errno.h>
18
#include <time.h>
19
#include <string.h>
20
#include <stdlib.h>
21
22
23
#ifdef __QNX__
# include <malloc.h> /* for malloc/free on QNX */
#endif
24
#include <cmsys/Glob.hxx>
25
#include <cmsys/RegularExpression.hxx>
Brad King's avatar
Brad King committed
26
#include <cmsys/Directory.hxx>
27
#include <cmsys/System.h>
28
#include <cmsys/Encoding.hxx>
29
#if defined(CMAKE_BUILD_WITH_CMAKE)
30
# include "cmArchiveWrite.h"
31
# include <cm_libarchive.h>
32
33
# include <cmsys/Terminal.h>
#endif
34
#include <cmsys/stl/algorithm>
35
#include <cmsys/FStream.hxx>
36

37
38
#if defined(_WIN32)
# include <windows.h>
39
# include <wincrypt.h>
40
#else
41
# include <sys/time.h>
42
43
44
# include <sys/types.h>
# include <unistd.h>
# include <utime.h>
45
# include <sys/wait.h>
46
47
#endif

48
49
50
51
#if defined(__APPLE__)
# include <mach-o/dyld.h>
#endif

52
53
#include <sys/stat.h>

Brad King's avatar
Brad King committed
54
55
56
#if defined(_WIN32) && \
   (defined(_MSC_VER) || defined(__WATCOMC__) || \
    defined(__BORLANDC__) || defined(__MINGW32__))
57
58
59
# include <io.h>
#endif

60
61
#if defined(CMAKE_BUILD_WITH_CMAKE)
#  include <fcntl.h>
62
#  include "cmCryptoHash.h"
63
64
#endif

Brad King's avatar
Brad King committed
65
66
67
68
#if defined(CMAKE_USE_ELF_PARSER)
# include "cmELF.h"
#endif

69
70
71
72
73
74
75
76
77
78
79
80
class cmSystemToolsFileTime
{
public:
#if defined(_WIN32) && !defined(__CYGWIN__)
  FILETIME timeCreation;
  FILETIME timeLastAccess;
  FILETIME timeLastWrite;
#else
  struct utimbuf timeBuf;
#endif
};

81
82
83
#if defined(__sgi) && !defined(__GNUC__)
# pragma set woff 1375 /* base class destructor not virtual */
#endif
84

Andy Cedilnik's avatar
Andy Cedilnik committed
85
#if !defined(HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE)
86
87
88
89
90
91
92
// For GetEnvironmentVariables
# if defined(_WIN32)
extern __declspec( dllimport ) char** environ;
# else
extern char** environ;
# endif
#endif
93

94
#ifdef _WIN32
95
96
97
98
99
100
101
102
103
104
105
106
class cmSystemToolsWindowsHandle
{
public:
  cmSystemToolsWindowsHandle(HANDLE h): handle_(h) {}
  ~cmSystemToolsWindowsHandle()
    {
    if(this->handle_ != INVALID_HANDLE_VALUE)
      {
      CloseHandle(this->handle_);
      }
    }
  operator bool() const { return this->handle_ != INVALID_HANDLE_VALUE; }
Ken Martin's avatar
Ken Martin committed
107
  bool operator !() const { return this->handle_ == INVALID_HANDLE_VALUE; }
108
109
110
111
  operator HANDLE() const { return this->handle_; }
private:
  HANDLE handle_;
};
112
113
114
#elif defined(__APPLE__)
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
115
116
#endif

117
bool cmSystemTools::s_RunCommandHideConsole = false;
118
bool cmSystemTools::s_DisableRunCommandOutput = false;
Bill Hoffman's avatar
Bill Hoffman committed
119
bool cmSystemTools::s_ErrorOccured = false;
120
bool cmSystemTools::s_FatalErrorOccured = false;
121
bool cmSystemTools::s_DisableMessages = false;
122
bool cmSystemTools::s_ForceUnixPaths = false;
Bill Hoffman's avatar
Bill Hoffman committed
123

124
void (*cmSystemTools::s_ErrorCallback)(const char*, const char*,
Ken Martin's avatar
Ken Martin committed
125
                                       bool&, void*);
126
void (*cmSystemTools::s_StdoutCallback)(const char*, int len, void*);
127
void* cmSystemTools::s_ErrorCallbackClientData = 0;
128
void* cmSystemTools::s_StdoutCallbackClientData = 0;
129
130
bool (*cmSystemTools::s_InterruptCallback)(void*);
void* cmSystemTools::s_InterruptCallbackClientData = 0;
131

Brad King's avatar
Brad King committed
132
133
// replace replace with with as many times as it shows up in source.
// write the result into source.
134
#if defined(_WIN32) && !defined(__CYGWIN__)
135
void cmSystemTools::ExpandRegistryValues(std::string& source, KeyWOW64 view)
Brad King's avatar
Brad King committed
136
137
138
139
140
141
142
{
  // Regular expression to match anything inside [...] that begins in HKEY.
  // Note that there is a special rule for regular expressions to match a
  // close square-bracket inside a list delimited by square brackets.
  // The "[^]]" part of this expression will match any character except
  // a close square-bracket.  The ']' character must be the first in the
  // list of characters inside the [^...] block of the expression.
143
  cmsys::RegularExpression regEntry("\\[(HKEY[^]]*)\\]");
144

Brad King's avatar
Brad King committed
145
146
  // check for black line or comment
  while (regEntry.find(source))
147
    {
Brad King's avatar
Brad King committed
148
149
150
    // the arguments are the second match
    std::string key = regEntry.match(1);
    std::string val;
151
    if (ReadRegistryValue(key.c_str(), val, view))
152
      {
Brad King's avatar
Brad King committed
153
154
155
      std::string reg = "[";
      reg += key + "]";
      cmSystemTools::ReplaceString(source, reg.c_str(), val.c_str());
156
157
158
      }
    else
      {
Brad King's avatar
Brad King committed
159
160
161
      std::string reg = "[";
      reg += key + "]";
      cmSystemTools::ReplaceString(source, reg.c_str(), "/registry");
162
163
164
      }
    }
}
165
#else
166
void cmSystemTools::ExpandRegistryValues(std::string& source, KeyWOW64)
Brad King's avatar
Brad King committed
167
{
168
169
170
171
172
173
174
175
176
177
178
  cmsys::RegularExpression regEntry("\\[(HKEY[^]]*)\\]");
  while (regEntry.find(source))
    {
    // the arguments are the second match
    std::string key = regEntry.match(1);
    std::string val;
    std::string reg = "[";
    reg += key + "]";
    cmSystemTools::ReplaceString(source, reg.c_str(), "/registry");
    }

179
}
Brad King's avatar
Brad King committed
180
#endif
181

Brad King's avatar
Brad King committed
182
std::string cmSystemTools::EscapeQuotes(const char* str)
183
{
Brad King's avatar
Brad King committed
184
185
  std::string result = "";
  for(const char* ch = str; *ch != '\0'; ++ch)
186
    {
Brad King's avatar
Brad King committed
187
    if(*ch == '"')
188
      {
Brad King's avatar
Brad King committed
189
      result += '\\';
190
      }
Brad King's avatar
Brad King committed
191
    result += *ch;
192
    }
Brad King's avatar
Brad King committed
193
  return result;
194
195
}

196
197
198
199
200
201
202
std::string cmSystemTools::HelpFileName(std::string name)
{
  cmSystemTools::ReplaceString(name, "<", "");
  cmSystemTools::ReplaceString(name, ">", "");
  return name;
}

203
204
205
std::string cmSystemTools::TrimWhitespace(const std::string& s)
{
  std::string::const_iterator start = s.begin();
206
  while(start != s.end() && *start <= ' ')
207
208
209
210
211
    ++start;
  if (start == s.end())
    return "";

  std::string::const_iterator stop = s.end()-1;
212
  while(*stop <= ' ')
213
214
215
216
    --stop;
  return std::string(start, stop+1);
}

Brad King's avatar
Brad King committed
217
218
219
220
221
void cmSystemTools::Error(const char* m1, const char* m2,
                          const char* m3, const char* m4)
{
  std::string message = "CMake Error: ";
  if(m1)
222
    {
Brad King's avatar
Brad King committed
223
    message += m1;
224
    }
Brad King's avatar
Brad King committed
225
  if(m2)
226
    {
Brad King's avatar
Brad King committed
227
    message += m2;
228
    }
Brad King's avatar
Brad King committed
229
  if(m3)
230
    {
Brad King's avatar
Brad King committed
231
    message += m3;
232
    }
Brad King's avatar
Brad King committed
233
  if(m4)
234
    {
Brad King's avatar
Brad King committed
235
    message += m4;
236
    }
Brad King's avatar
Brad King committed
237
238
239
240
  cmSystemTools::s_ErrorOccured = true;
  cmSystemTools::Message(message.c_str(),"Error");
}

241
242
243
244
245
246
247
248
249
250
251
252
253
254
void cmSystemTools::SetInterruptCallback(InterruptCallback f, void* clientData)
{
  s_InterruptCallback = f;
  s_InterruptCallbackClientData = clientData;
}

bool cmSystemTools::GetInterruptFlag()
{
  if(s_InterruptCallback)
    {
    return (*s_InterruptCallback)(s_InterruptCallbackClientData);
    }
  return false;
}
Brad King's avatar
Brad King committed
255
256
257
258
259
260
261

void cmSystemTools::SetErrorCallback(ErrorCallback f, void* clientData)
{
  s_ErrorCallback = f;
  s_ErrorCallbackClientData = clientData;
}

262
263
264
265
266
267
268
269
270
271
void cmSystemTools::SetStdoutCallback(StdoutCallback f, void* clientData)
{
  s_StdoutCallback = f;
  s_StdoutCallbackClientData = clientData;
}

void cmSystemTools::Stdout(const char* s)
{
  if(s_StdoutCallback)
    {
272
    (*s_StdoutCallback)(s, static_cast<int>(strlen(s)),
Bill Hoffman's avatar
Bill Hoffman committed
273
                        s_StdoutCallbackClientData);
274
275
276
277
    }
  else
    {
    std::cout << s;
278
    std::cout.flush();
279
280
281
    }
}

282
283
284
285
286
287
void cmSystemTools::Stderr(const char* s, int length)
{
    std::cerr.write(s, length);
    std::cerr.flush();
}

288
289
290
291
292
293
294
295
296
void cmSystemTools::Stdout(const char* s, int length)
{
  if(s_StdoutCallback)
    {
    (*s_StdoutCallback)(s, length, s_StdoutCallbackClientData);
    }
  else
    {
    std::cout.write(s, length);
297
    std::cout.flush();
298
299
300
    }
}

Brad King's avatar
Brad King committed
301
302
303
void cmSystemTools::Message(const char* m1, const char *title)
{
  if(s_DisableMessages)
304
    {
Brad King's avatar
Brad King committed
305
    return;
306
    }
Brad King's avatar
Brad King committed
307
  if(s_ErrorCallback)
308
    {
309
    (*s_ErrorCallback)(m1, title, s_DisableMessages,
Bill Hoffman's avatar
Bill Hoffman committed
310
                       s_ErrorCallbackClientData);
Brad King's avatar
Brad King committed
311
    return;
312
313
314
    }
  else
    {
Brad King's avatar
Brad King committed
315
    std::cerr << m1 << std::endl << std::flush;
316
    }
317

Brad King's avatar
Brad King committed
318
}
319
320


Brad King's avatar
Brad King committed
321
void cmSystemTools::ReportLastSystemError(const char* msg)
322
{
Brad King's avatar
Brad King committed
323
324
  std::string m = msg;
  m += ": System Error: ";
325
  m += Superclass::GetLastSystemError();
Brad King's avatar
Brad King committed
326
327
328
  cmSystemTools::Error(m.c_str());
}

329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
bool cmSystemTools::IsInternallyOn(const char* val)
{
  if (!val)
    {
    return false;
    }
  std::basic_string<char> v = val;

  for(std::basic_string<char>::iterator c = v.begin();
      c != v.end(); c++)
    {
    *c = static_cast<char>(toupper(*c));
    }
  return (v == "I_ON" || v == "i_on");
}

Brad King's avatar
Brad King committed
345
346
347
bool cmSystemTools::IsOn(const char* val)
{
  if (!val)
348
349
350
    {
    return false;
    }
Brad King's avatar
Brad King committed
351
  std::basic_string<char> v = val;
352

Brad King's avatar
Brad King committed
353
354
  for(std::basic_string<char>::iterator c = v.begin();
      c != v.end(); c++)
355
    {
356
    *c = static_cast<char>(toupper(*c));
357
    }
Brad King's avatar
Brad King committed
358
359
  return (v == "ON" || v == "1" || v == "YES" || v == "TRUE" || v == "Y");
}
360

Brad King's avatar
Brad King committed
361
362
bool cmSystemTools::IsNOTFOUND(const char* val)
{
Stephen Kelly's avatar
Stephen Kelly committed
363
  if(strcmp(val, "NOTFOUND") == 0)
364
    {
Stephen Kelly's avatar
Stephen Kelly committed
365
    return true;
366
    }
Stephen Kelly's avatar
Stephen Kelly committed
367
  return cmHasLiteralSuffix(val, "-NOTFOUND");
Brad King's avatar
Brad King committed
368
}
369
370


Brad King's avatar
Brad King committed
371
bool cmSystemTools::IsOff(const char* val)
372
{
Brad King's avatar
Brad King committed
373
  if (!val || strlen(val) == 0)
374
    {
Brad King's avatar
Brad King committed
375
    return true;
376
    }
Brad King's avatar
Brad King committed
377
  std::basic_string<char> v = val;
378

Brad King's avatar
Brad King committed
379
380
  for(std::basic_string<char>::iterator c = v.begin();
      c != v.end(); c++)
381
    {
382
    *c = static_cast<char>(toupper(*c));
383
    }
384
  return (v == "OFF" || v == "0" || v == "NO" || v == "FALSE" ||
Brad King's avatar
Brad King committed
385
          v == "N" || cmSystemTools::IsNOTFOUND(v.c_str()) || v == "IGNORE");
386
387
}

388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
//----------------------------------------------------------------------------
void cmSystemTools::ParseWindowsCommandLine(const char* command,
                                            std::vector<std::string>& args)
{
  // See the MSDN document "Parsing C Command-Line Arguments" at
  // http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx for rules
  // of parsing the windows command line.

  bool in_argument = false;
  bool in_quotes = false;
  int backslashes = 0;
  std::string arg;
  for(const char* c = command;*c; ++c)
    {
    if(*c == '\\')
      {
      ++backslashes;
      in_argument = true;
      }
    else if(*c == '"')
      {
      int backslash_pairs  = backslashes >> 1;
      int backslash_escaped = backslashes & 1;
      arg.append(backslash_pairs, '\\');
      backslashes = 0;
      if(backslash_escaped)
        {
        /* An odd number of backslashes precede this quote.
           It is escaped.  */
        arg.append(1, '"');
        }
      else
        {
        /* An even number of backslashes precede this quote.
           It is not escaped.  */
        in_quotes = !in_quotes;
        }
      in_argument = true;
      }
    else
      {
      arg.append(backslashes, '\\');
      backslashes = 0;
      if(isspace(*c))
        {
        if(in_quotes)
          {
          arg.append(1, *c);
          }
        else if(in_argument)
          {
          args.push_back(arg);
          arg = "";
          in_argument = false;
          }
        }
      else
        {
        in_argument = true;
        arg.append(1, *c);
        }
      }
    }
  arg.append(backslashes, '\\');
  if(in_argument)
    {
    args.push_back(arg);
    }
}

458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
//----------------------------------------------------------------------------
class cmSystemToolsArgV
{
  char** ArgV;
public:
  cmSystemToolsArgV(char** argv): ArgV(argv) {}
  ~cmSystemToolsArgV()
    {
    for(char** arg = this->ArgV; arg && *arg; ++arg)
      {
      free(*arg);
      }
    free(this->ArgV);
    }
  void Store(std::vector<std::string>& args) const
    {
    for(char** arg = this->ArgV; arg && *arg; ++arg)
      {
      args.push_back(*arg);
      }
    }
479
480
481
482
483
484
485
  void Store(std::vector<cmStdString>& args) const
    {
    for(char** arg = this->ArgV; arg && *arg; ++arg)
      {
      args.push_back(*arg);
      }
    }
486
487
488
489
490
491
492
493
494
495
496
};

//----------------------------------------------------------------------------
void cmSystemTools::ParseUnixCommandLine(const char* command,
                                         std::vector<std::string>& args)
{
  // Invoke the underlying parser.
  cmSystemToolsArgV argv = cmsysSystem_Parse_CommandForUnix(command, 0);
  argv.Store(args);
}

497
498
499
500
501
502
503
504
505
//----------------------------------------------------------------------------
void cmSystemTools::ParseUnixCommandLine(const char* command,
                                         std::vector<cmStdString>& args)
{
  // Invoke the underlying parser.
  cmSystemToolsArgV argv = cmsysSystem_Parse_CommandForUnix(command, 0);
  argv.Store(args);
}

506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
std::string cmSystemTools::EscapeWindowsShellArgument(const char* arg,
                                                      int shell_flags)
{
  char local_buffer[1024];
  char* buffer = local_buffer;
  int size = cmsysSystem_Shell_GetArgumentSizeForWindows(arg, shell_flags);
  if(size > 1024)
    {
    buffer = new char[size];
    }
  cmsysSystem_Shell_GetArgumentForWindows(arg, buffer, shell_flags);
  std::string result(buffer);
  if(buffer != local_buffer)
    {
    delete [] buffer;
    }
  return result;
}

525
std::vector<cmStdString> cmSystemTools::ParseArguments(const char* command)
526
{
527
  std::vector<cmStdString> args;
528
  std::string arg;
529

Andy Cedilnik's avatar
Andy Cedilnik committed
530
531
  bool win_path = false;

532
533
534
535
536
537
  if ((command[0] != '/' && command[1] == ':' && command[2] == '\\') ||
      (command[0] == '\"' && command[1] != '/' && command[2] == ':'
       && command[3] == '\\') ||
      (command[0] == '\'' && command[1] != '/' && command[2] == ':'
       && command[3] == '\\') ||
      (command[0] == '\\' && command[1] == '\\'))
Andy Cedilnik's avatar
Andy Cedilnik committed
538
539
540
    {
    win_path = true;
    }
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
  // Split the command into an argv array.
  for(const char* c = command; *c;)
    {
    // Skip over whitespace.
    while(*c == ' ' || *c == '\t')
      {
      ++c;
      }
    arg = "";
    if(*c == '"')
      {
      // Parse a quoted argument.
      ++c;
      while(*c && *c != '"')
        {
Andy Cedilnik's avatar
Andy Cedilnik committed
556
557
        arg.append(1, *c);
        ++c;
558
559
560
561
562
563
564
        }
      if(*c)
        {
        ++c;
        }
      args.push_back(arg);
      }
Andy Cedilnik's avatar
Andy Cedilnik committed
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
    else if(*c == '\'')
      {
      // Parse a quoted argument.
      ++c;
      while(*c && *c != '\'')
        {
        arg.append(1, *c);
        ++c;
        }
      if(*c)
        {
        ++c;
        }
      args.push_back(arg);
      }
580
581
582
583
584
    else if(*c)
      {
      // Parse an unquoted argument.
      while(*c && *c != ' ' && *c != '\t')
        {
Andy Cedilnik's avatar
Andy Cedilnik committed
585
        if(*c == '\\' && !win_path)
586
587
588
589
590
591
592
593
594
595
596
597
598
          {
          ++c;
          if(*c)
            {
            arg.append(1, *c);
            ++c;
            }
          }
        else
          {
          arg.append(1, *c);
          ++c;
          }
599
600
601
602
        }
      args.push_back(arg);
      }
    }
603

604
605
606
  return args;
}

607

608
609
bool cmSystemTools::RunSingleCommand(std::vector<cmStdString>const& command,
                                     std::string* output ,
610
                                     int* retVal , const char* dir ,
611
                                     OutputOption outputflag ,
612
                                     double timeout )
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
{
  std::vector<std::string> cmd;
  for(std::vector<cmStdString>::const_iterator i = command.begin();
      i != command.end(); ++i)
    {
    cmd.push_back(*i);
    }
  return cmSystemTools::RunSingleCommand(cmd, output, retVal, dir,
                                         outputflag, timeout);
}

bool cmSystemTools::RunSingleCommand(std::vector<std::string>const& command,
                                     std::string* output ,
                                     int* retVal , const char* dir ,
                                     OutputOption outputflag ,
                                     double timeout )
629
{
630
  std::vector<const char*> argv;
631
  for(std::vector<std::string>::const_iterator a = command.begin();
632
      a != command.end(); ++a)
633
634
635
636
    {
    argv.push_back(a->c_str());
    }
  argv.push_back(0);
637
638
639
640
  if ( output )
    {
    *output = "";
    }
641

642
643
644
  cmsysProcess* cp = cmsysProcess_New();
  cmsysProcess_SetCommand(cp, &*argv.begin());
  cmsysProcess_SetWorkingDirectory(cp, dir);
645
646
647
648
  if(cmSystemTools::GetRunCommandHideConsole())
    {
    cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
    }
649

650
651
652
653
654
655
  if (outputflag == OUTPUT_PASSTHROUGH)
    {
    cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
    cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
    }

656
657
  cmsysProcess_SetTimeout(cp, timeout);
  cmsysProcess_Execute(cp);
658

659
  std::vector<char> tempOutput;
660
661
  char* data;
  int length;
662
  int pipe;
663
  if(outputflag != OUTPUT_PASSTHROUGH && (output || outputflag != OUTPUT_NONE))
664
    {
665
    while((pipe = cmsysProcess_WaitForData(cp, &data, &length, 0)) > 0)
666
      {
667
      if(output || outputflag != OUTPUT_NONE)
668
        {
Brad King's avatar
Brad King committed
669
670
671
672
        // Translate NULL characters in the output into valid text.
        // Visual Studio 7 puts these characters in the output of its
        // build process.
        for(int i=0; i < length; ++i)
673
          {
Brad King's avatar
Brad King committed
674
675
676
677
          if(data[i] == '\0')
            {
            data[i] = ' ';
            }
678
679
          }
        }
Brad King's avatar
Brad King committed
680
681
682
683
      if ( output )
        {
        tempOutput.insert(tempOutput.end(), data, data+length);
        }
684
      if(outputflag != OUTPUT_NONE)
Brad King's avatar
Brad King committed
685
        {
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
        if(outputflag == OUTPUT_MERGE)
          {
          cmSystemTools::Stdout(data, length);
          }
        else
          {
          if(pipe == cmsysProcess_Pipe_STDERR)
            {
            cmSystemTools::Stderr(data, length);
            }
          else if(pipe == cmsysProcess_Pipe_STDOUT)
            {
            cmSystemTools::Stdout(data, length);
            }
          }
Brad King's avatar
Brad King committed
701
        }
702
      }
703
    }
704

705
  cmsysProcess_WaitForExit(cp, 0);
706
  if ( output && tempOutput.begin() != tempOutput.end())
707
708
709
    {
    output->append(&*tempOutput.begin(), tempOutput.size());
    }
710

711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
  bool result = true;
  if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exited)
    {
    if ( retVal )
      {
      *retVal = cmsysProcess_GetExitValue(cp);
      }
    else
      {
      if ( cmsysProcess_GetExitValue(cp) !=  0 )
        {
        result = false;
        }
      }
    }
726
727
  else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exception)
    {
728
    const char* exception_str = cmsysProcess_GetExceptionString(cp);
729
    if ( outputflag != OUTPUT_NONE )
730
731
732
      {
      std::cerr << exception_str << std::endl;
      }
733
734
735
736
    if ( output )
      {
      output->append(exception_str, strlen(exception_str));
      }
737
738
    result = false;
    }
739
  else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Error)
740
    {
741
    const char* error_str = cmsysProcess_GetErrorString(cp);
742
    if ( outputflag != OUTPUT_NONE )
743
744
745
      {
      std::cerr << error_str << std::endl;
      }
746
747
748
749
    if ( output )
      {
      output->append(error_str, strlen(error_str));
      }
750
751
    result = false;
    }
752
753
  else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Expired)
    {
754
    const char* error_str = "Process terminated due to timeout\n";
755
    if ( outputflag != OUTPUT_NONE )
756
757
758
      {
      std::cerr << error_str << std::endl;
      }
759
760
761
762
    if ( output )
      {
      output->append(error_str, strlen(error_str));
      }
763
764
    result = false;
    }
765

766
767
768
  cmsysProcess_Delete(cp);
  return result;
}
769
770

bool cmSystemTools::RunSingleCommand(
771
  const char* command,
772
  std::string* output,
773
  int *retVal,
774
  const char* dir,
775
  OutputOption outputflag,
776
777
778
779
  double timeout)
{
  if(s_DisableRunCommandOutput)
    {
780
    outputflag = OUTPUT_NONE;
781
782
783
784
785
786
787
788
    }

  std::vector<cmStdString> args = cmSystemTools::ParseArguments(command);

  if(args.size() < 1)
    {
    return false;
    }
789
  return cmSystemTools::RunSingleCommand(args, output,retVal,
790
                                         dir, outputflag, timeout);
791
}
792

793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
std::string
cmSystemTools::PrintSingleCommand(std::vector<std::string> const& command)
{
  std::string commandStr;
  const char* sep = "";
  for(std::vector<std::string>::const_iterator i = command.begin();
      i != command.end(); ++i)
    {
    commandStr += sep;
    commandStr += "\"";
    commandStr += *i;
    commandStr += "\"";
    sep = " ";
    }
  return commandStr;
}

Brad King's avatar
Brad King committed
810
811
812
bool cmSystemTools::DoesFileExistWithExtensions(
  const char* name,
  const std::vector<std::string>& headerExts)
813
{
Brad King's avatar
Brad King committed
814
815
816
817
  std::string hname;

  for( std::vector<std::string>::const_iterator ext = headerExts.begin();
       ext != headerExts.end(); ++ext )
818
    {
Brad King's avatar
Brad King committed
819
820
821
822
823
824
825
    hname = name;
    hname += ".";
    hname += *ext;
    if(cmSystemTools::FileExists(hname.c_str()))
      {
      return true;
      }
826
    }
Brad King's avatar
Brad King committed
827
  return false;
828
829
}

830
831
832
833
std::string cmSystemTools::FileExistsInParentDirectories(const char* fname,
  const char* directory, const char* toplevel)
{
  std::string file = fname;
834
  cmSystemTools::ConvertToUnixSlashes(file);
835
  std::string dir = directory;
836
  cmSystemTools::ConvertToUnixSlashes(dir);
837
838
  std::string prevDir;
  while(dir != prevDir)
839
840
    {
    std::string path = dir + "/" + file;
841
    if ( cmSystemTools::FileExists(path.c_str()) )
842
843
844
845
846
847
848
      {
      return path;
      }
    if ( dir.size() < strlen(toplevel) )
      {
      break;
      }
849
    prevDir = dir;
850
    dir = cmSystemTools::GetParentDirectory(dir.c_str());
851
852
853
854
    }
  return "";
}

Brad King's avatar
Brad King committed
855
bool cmSystemTools::cmCopyFile(const char* source, const char* destination)
856
{
857
  return Superclass::CopyFileAlways(source, destination);
858
859
}

860
bool cmSystemTools::CopyFileIfDifferent(const char* source,
861
862
  const char* destination)
{
863
  return Superclass::CopyFileIfDifferent(source, destination);
864
}
865

866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
//----------------------------------------------------------------------------
#ifdef _WIN32
cmSystemTools::WindowsFileRetry cmSystemTools::GetWindowsFileRetry()
{
  static WindowsFileRetry retry = {0,0};
  if(!retry.Count)
    {
    unsigned int data[2] = {0,0};
    HKEY const keys[2] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE};
    wchar_t const* const values[2] = {L"FilesystemRetryCount",
                                      L"FilesystemRetryDelay"};
    for(int k=0; k < 2; ++k)
      {
      HKEY hKey;
      if(RegOpenKeyExW(keys[k], L"Software\\Kitware\\CMake\\Config",
                       0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
        {
        for(int v=0; v < 2; ++v)
          {
          DWORD dwData, dwType, dwSize = 4;
          if(!data[v] &&
             RegQueryValueExW(hKey, values[v], 0, &dwType, (BYTE *)&dwData,
                              &dwSize) == ERROR_SUCCESS &&
             dwType == REG_DWORD && dwSize == 4)
            {
            data[v] = static_cast<unsigned int>(dwData);
            }
          }
        RegCloseKey(hKey);
        }
      }
    retry.Count = data[0]? data[0] : 5;
    retry.Delay = data[1]? data[1] : 500;
    }
  return retry;
}
#endif

904
905
906
907
//----------------------------------------------------------------------------
bool cmSystemTools::RenameFile(const char* oldname, const char* newname)
{
#ifdef _WIN32
908
909
910
911
912
913
914
# ifndef INVALID_FILE_ATTRIBUTES
#  define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
# endif
  /* Windows MoveFileEx may not replace read-only or in-use files.  If it
     fails then remove the read-only attribute from any existing destination.
     Try multiple times since we may be racing against another process
     creating/opening the destination file just before our MoveFileEx.  */
915
  WindowsFileRetry retry = cmSystemTools::GetWindowsFileRetry();
916
917
  while(!MoveFileExW(cmsys::Encoding::ToWide(oldname).c_str(),
                     cmsys::Encoding::ToWide(newname).c_str(),
918
                     MOVEFILE_REPLACE_EXISTING) && --retry.Count)
919
    {
920
921
922
923
    DWORD last_error = GetLastError();
    // Try again only if failure was due to access/sharing permissions.
    if(last_error != ERROR_ACCESS_DENIED &&
       last_error != ERROR_SHARING_VIOLATION)
924
      {
925
      return false;
926
      }
927
928
    DWORD attrs =
      GetFileAttributesW(cmsys::Encoding::ToWide(newname).c_str());
929
930
    if((attrs != INVALID_FILE_ATTRIBUTES) &&
       (attrs & FILE_ATTRIBUTE_READONLY))
931
      {
932
      // Remove the read-only attribute from the destination file.
933
934
      SetFileAttributesW(cmsys::Encoding::ToWide(newname).c_str(),
                         attrs & ~FILE_ATTRIBUTE_READONLY);
935
936
937
      }
    else
      {
938
      // The file may be temporarily in use so wait a bit.
939
      cmSystemTools::Delay(retry.Delay);
940
941
      }
    }
942
  return retry.Count > 0;
943
944
945
946
947
948
#else
  /* On UNIX we have an OS-provided call to do this atomically.  */
  return rename(oldname, newname) == 0;
#endif
}

Alexander Neundorf's avatar
   
Alexander Neundorf committed
949
950
bool cmSystemTools::ComputeFileMD5(const char* source, char* md5out)
{
Alexander Neundorf's avatar
   
Alexander Neundorf committed
951
#if defined(CMAKE_BUILD_WITH_CMAKE)
952
953
954
955
  cmCryptoHashMD5 md5;
  std::string str = md5.HashFile(source);
  strncpy(md5out, str.c_str(), 32);
  return !str.empty();
Alexander Neundorf's avatar
   
Alexander Neundorf committed
956
957
958
#else
  (void)source;
  (void)md5out;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
959
960
961
  cmSystemTools::Message("md5sum not supported in bootstrapping mode","Error");
  return false;
#endif
Alexander Neundorf's avatar
   
Alexander Neundorf committed
962
963
}

964
965
std::string cmSystemTools::ComputeStringMD5(const char* input)
{
966
#if defined(CMAKE_BUILD_WITH_CMAKE)
967
968
  cmCryptoHashMD5 md5;
  return md5.HashString(input);
969
970
971
#else
  (void)input;
  cmSystemTools::Message("md5sum not supported in bootstrapping mode","Error");
972
  return "";
973
#endif
974
975
}

Ken Martin's avatar
Ken Martin committed
976
977
978
void cmSystemTools::Glob(const char *directory, const char *regexp,
                         std::vector<std::string>& files)
{
Brad King's avatar
Brad King committed
979
  cmsys::Directory d;
980
  cmsys::RegularExpression reg(regexp);
981

Ken Martin's avatar
Ken Martin committed
982
983
  if (d.Load(directory))
    {
984
    size_t numf;
985
        unsigned int i;
Ken Martin's avatar
Ken Martin committed
986
987
988
989
990
991
992
993
994
995
996
997
    numf = d.GetNumberOfFiles();
    for (i = 0; i < numf; i++)
      {
      std::string fname = d.GetFile(i);
      if (reg.find(fname))
        {
        files.push_back(fname);
        }
      }
    }
}

998
999
1000
1001
1002

void cmSystemTools::GlobDirs(const char *fullPath,
                             std::vector<std::string>& files)
{
  std::string path = fullPath;
Bill Hoffman's avatar
Bill Hoffman committed
1003
  std::string::size_type pos = path.find("/*");
1004
1005
1006
1007
1008
1009
1010
1011
  if(pos == std::string::npos)
    {
    files.push_back(fullPath);
    return;
    }
  std::string startPath = path.substr(0, pos);
  std::string finishPath = path.substr(pos+2);

Brad King's avatar
Brad King committed
1012
  cmsys::Directory d;
1013
1014
  if (d.Load(startPath.c_str()))
    {
Bill Hoffman's avatar
Bill Hoffman committed
1015
    for (unsigned int i = 0; i < d.GetNumberOfFiles(); ++i)
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
      {
      if((std::string(d.GetFile(i)) != ".")
         && (std::string(d.GetFile(i)) != ".."))
        {
        std::string fname = startPath;
        fname +="/";
        fname += d.GetFile(i);
        if(cmSystemTools::FileIsDirectory(fname.c_str()))
          {
          fname += finishPath;
          cmSystemTools::GlobDirs(fname.c_str(), files);
          }
        }
      }
    }
}
1032
1033


1034
void cmSystemTools::ExpandList(std::vector<std::string> const& arguments,
1035
                               std::vector<std::string>& newargs)
1036
1037
1038
1039
{
  std::vector<std::string>::const_iterator i;
  for(i = arguments.begin();i != arguments.end(); ++i)
    {
1040
1041
1042
1043
1044
    cmSystemTools::ExpandListArgument(*i, newargs);
    }
}

void cmSystemTools::ExpandListArgument(const std::string& arg,
1045
1046
                                       std::vector<std::string>& newargs,
                                       bool emptyArgs)
1047
1048
{
  // If argument is empty, it is an empty list.
1049
  if(arg.length() == 0 && !emptyArgs)
1050
1051
1052
1053
1054
1055
1056
    {
    return;
    }
  // if there are no ; in the name then just copy the current string
  if(arg.find(';') == std::string::npos)
    {
    newargs.push_back(arg);
1057
    return;
1058
    }
1059
  std::vector<char> newArgVec;
1060
1061
1062
  // Break the string at non-escaped semicolons not nested in [].
  int squareNesting = 0;
  for(const char* c = arg.c_str(); *c; ++c)
1063
    {
1064
    switch(*c)
1065
      {
1066
      case '\\':
1067
        {
1068
1069
1070
1071
        // We only want to allow escaping of semicolons.  Other
        // escapes should not be processed here.
        ++c;
        if(*c == ';')
1072
          {
1073
          newArgVec.push_back(*c);
1074
          }
1075
        else
1076
          {
1077
          newArgVec.push_back('\\');
1078
          if(*c)
1079
            {
1080
            newArgVec.push_back(*c);
1081
            }
1082
1083
1084
1085
1086
          else
            {
            // Terminate the loop properly.
            --c;
            }
1087
1088
1089
1090
1091
          }
        } break;
      case '[':
        {
        ++squareNesting;
1092
        newArgVec.push_back(*c);
1093
1094
1095
        } break;
      case ']':
        {
1096
        --squareNesting;
1097
        newArgVec.push_back(*c);
1098
1099
1100
1101
1102
1103
1104
        } break;
      case ';':
        {
        // Break the string here if we are not nested inside square
        // brackets.
        if(squareNesting == 0)
          {
1105
          if ( newArgVec.size() || emptyArgs )
1106
            {
Andy Cedilnik's avatar