cmSystemTools.cxx 35.5 KB
Newer Older
1
2
/*=========================================================================

3
  Program:   CMake - Cross-Platform Makefile Generator
4
5
6
7
8
  Module:    $RCSfile$
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

9
10
  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
11

Will Schroeder's avatar
Will Schroeder committed
12
13
14
     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.
15
16

=========================================================================*/
17
#include "cmSystemTools.h"   
Ken Martin's avatar
Ken Martin committed
18
#include <ctype.h>
19
#include <errno.h>
20
#include <time.h>
21

22
#include <cmsys/RegularExpression.hxx>
Brad King's avatar
Brad King committed
23
#include <cmsys/Directory.hxx>
24
#include <cmsys/Process.h>
25

26
27
28
29
30
// support for realpath call
#ifndef _WIN32
#include <limits.h>
#include <stdlib.h>
#include <sys/param.h>
31
#include <sys/wait.h>
32
33
#endif

34
#if defined(_WIN32) && (defined(_MSC_VER) || defined(__BORLANDC__))
35
#include <string.h>
36
#include <windows.h>
37
#include <direct.h>
38
#include <io.h>
Bill Hoffman's avatar
Bill Hoffman committed
39
#define _unlink unlink
40
41
42
43
44
45
#else
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#endif

46
47
#include <sys/stat.h>

48
49
50
#if defined(__sgi) && !defined(__GNUC__)
# pragma set woff 1375 /* base class destructor not virtual */
#endif
51

52
bool cmSystemTools::s_RunCommandHideConsole = false;
53
bool cmSystemTools::s_DisableRunCommandOutput = false;
Bill Hoffman's avatar
Bill Hoffman committed
54
bool cmSystemTools::s_ErrorOccured = false;
55
bool cmSystemTools::s_FatalErrorOccured = false;
56
bool cmSystemTools::s_DisableMessages = false;
57
bool cmSystemTools::s_ForceUnixPaths = false;
Bill Hoffman's avatar
Bill Hoffman committed
58

59
60
61
62
63
64
65
66
67
68
69
70
71
std::string cmSystemTools::s_Windows9xComspecSubstitute = "command.com";
void cmSystemTools::SetWindows9xComspecSubstitute(const char* str)
{
  if ( str )
    {
    cmSystemTools::s_Windows9xComspecSubstitute = str;
    }
}
const char* cmSystemTools::GetWindows9xComspecSubstitute()
{
  return cmSystemTools::s_Windows9xComspecSubstitute.c_str();
}

72
void (*cmSystemTools::s_ErrorCallback)(const char*, const char*, bool&, void*);
73
void (*cmSystemTools::s_StdoutCallback)(const char*, int len, void*);
74
void* cmSystemTools::s_ErrorCallbackClientData = 0;
75
void* cmSystemTools::s_StdoutCallbackClientData = 0;
76

Brad King's avatar
Brad King committed
77
78
// replace replace with with as many times as it shows up in source.
// write the result into source.
79
#if defined(_WIN32) && !defined(__CYGWIN__)
Brad King's avatar
Brad King committed
80
81
82
83
84
85
86
87
void cmSystemTools::ExpandRegistryValues(std::string& source)
{
  // 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.
88
  cmsys::RegularExpression regEntry("\\[(HKEY[^]]*)\\]");
Brad King's avatar
Brad King committed
89
90
91
  
  // check for black line or comment
  while (regEntry.find(source))
92
    {
Brad King's avatar
Brad King committed
93
94
95
96
    // the arguments are the second match
    std::string key = regEntry.match(1);
    std::string val;
    if (ReadRegistryValue(key.c_str(), val))
97
      {
Brad King's avatar
Brad King committed
98
99
100
      std::string reg = "[";
      reg += key + "]";
      cmSystemTools::ReplaceString(source, reg.c_str(), val.c_str());
101
102
103
      }
    else
      {
Brad King's avatar
Brad King committed
104
105
106
      std::string reg = "[";
      reg += key + "]";
      cmSystemTools::ReplaceString(source, reg.c_str(), "/registry");
107
108
109
      }
    }
}
110
#else
Brad King's avatar
Brad King committed
111
112
void cmSystemTools::ExpandRegistryValues(std::string&)
{
113
}
Brad King's avatar
Brad King committed
114
#endif
115

Brad King's avatar
Brad King committed
116
std::string cmSystemTools::EscapeQuotes(const char* str)
117
{
Brad King's avatar
Brad King committed
118
119
  std::string result = "";
  for(const char* ch = str; *ch != '\0'; ++ch)
120
    {
Brad King's avatar
Brad King committed
121
    if(*ch == '"')
122
      {
Brad King's avatar
Brad King committed
123
      result += '\\';
124
      }
Brad King's avatar
Brad King committed
125
    result += *ch;
126
    }
Brad King's avatar
Brad King committed
127
  return result;
128
129
}

Brad King's avatar
Brad King committed
130
std::string cmSystemTools::EscapeSpaces(const char* str)
131
{
Brad King's avatar
Brad King committed
132
#if defined(_WIN32) && !defined(__CYGWIN__)
133
134
135
136
137
138
139
140
  bool useDoubleQ = true;
#else
  bool useDoubleQ = false;
#endif
  if(cmSystemTools::s_ForceUnixPaths)
    {
    useDoubleQ = false;
    }
Brad King's avatar
Brad King committed
141
  
142
  if(useDoubleQ)
143
    {
144
145
146
147
148
149
150
151
152
153
154
155
156
    std::string result;
    
    // if there are spaces
    std::string temp = str;
    if (temp.find(" ") != std::string::npos && 
        temp.find("\"")==std::string::npos)
      {
      result = "\"";
      result += str;
      result += "\"";
      return result;
      }
    return str;
157
    }
158
  else
159
    {
160
161
    std::string result = "";
    for(const char* ch = str; *ch != '\0'; ++ch)
Brad King's avatar
Brad King committed
162
      {
163
164
165
166
167
      if(*ch == ' ')
        {
        result += '\\';
        }
      result += *ch;
Brad King's avatar
Brad King committed
168
      }
169
    return result;
170
171
    }
}
172

173

Brad King's avatar
Brad King committed
174
std::string cmSystemTools::RemoveEscapes(const char* s)
175
{
Brad King's avatar
Brad King committed
176
177
  std::string result = "";
  for(const char* ch = s; *ch; ++ch)
178
    {
Brad King's avatar
Brad King committed
179
180
181
182
183
184
185
186
187
188
189
    if(*ch == '\\' && *(ch+1) != ';')
      {
      ++ch;
      switch (*ch)
        {
        case '\\': result.insert(result.end(), '\\'); break;
        case '"': result.insert(result.end(), '"'); break;
        case ' ': result.insert(result.end(), ' '); break;
        case 't': result.insert(result.end(), '\t'); break;
        case 'n': result.insert(result.end(), '\n'); break;
        case 'r': result.insert(result.end(), '\r'); break;
190
        case '#': result.insert(result.end(), '#'); break;
191
192
        case '(': result.insert(result.end(), '('); break;
        case ')': result.insert(result.end(), ')'); break;
Brad King's avatar
Brad King committed
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
        case '0': result.insert(result.end(), '\0'); break;
        case '\0':
          {
          cmSystemTools::Error("Trailing backslash in argument:\n", s);
          return result;
          }
        default:
          {
          std::string chStr(1, *ch);
          cmSystemTools::Error("Invalid escape sequence \\", chStr.c_str(),
                               "\nin argument ", s);
          }
        }
      }
    else
      {
      result.insert(result.end(), *ch);
      }
211
    }
Brad King's avatar
Brad King committed
212
213
  return result;
}
214

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


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

246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
void cmSystemTools::SetStdoutCallback(StdoutCallback f, void* clientData)
{
  s_StdoutCallback = f;
  s_StdoutCallbackClientData = clientData;
}

void cmSystemTools::Stdout(const char* s)
{
  if(s_StdoutCallback)
    {
    (*s_StdoutCallback)(s, strlen(s), s_StdoutCallbackClientData);
    }
  else
    {
    std::cout << s;
261
    std::cout.flush();
262
263
264
265
266
267
268
269
270
271
272
273
    }
}

void cmSystemTools::Stdout(const char* s, int length)
{
  if(s_StdoutCallback)
    {
    (*s_StdoutCallback)(s, length, s_StdoutCallbackClientData);
    }
  else
    {
    std::cout.write(s, length);
274
    std::cout.flush();
275
276
277
    }
}

Brad King's avatar
Brad King committed
278
279
280
void cmSystemTools::Message(const char* m1, const char *title)
{
  if(s_DisableMessages)
281
    {
Brad King's avatar
Brad King committed
282
    return;
283
    }
Brad King's avatar
Brad King committed
284
  if(s_ErrorCallback)
285
    {
Brad King's avatar
Brad King committed
286
287
    (*s_ErrorCallback)(m1, title, s_DisableMessages, s_ErrorCallbackClientData);
    return;
288
289
290
    }
  else
    {
Brad King's avatar
Brad King committed
291
    std::cerr << m1 << std::endl << std::flush;
292
    }
Brad King's avatar
Brad King committed
293
  
Brad King's avatar
Brad King committed
294
}
295
296


Brad King's avatar
Brad King committed
297
void cmSystemTools::ReportLastSystemError(const char* msg)
298
{
Brad King's avatar
Brad King committed
299
300
  std::string m = msg;
  m += ": System Error: ";
301
  m += Superclass::GetLastSystemError();
Brad King's avatar
Brad King committed
302
303
304
  cmSystemTools::Error(m.c_str());
}

305
 
Brad King's avatar
Brad King committed
306
307
308
bool cmSystemTools::IsOn(const char* val)
{
  if (!val)
309
310
311
    {
    return false;
    }
Brad King's avatar
Brad King committed
312
  std::basic_string<char> v = val;
313
  
Brad King's avatar
Brad King committed
314
315
  for(std::basic_string<char>::iterator c = v.begin();
      c != v.end(); c++)
316
    {
Brad King's avatar
Brad King committed
317
    *c = toupper(*c);
318
    }
Brad King's avatar
Brad King committed
319
320
  return (v == "ON" || v == "1" || v == "YES" || v == "TRUE" || v == "Y");
}
321

Brad King's avatar
Brad King committed
322
323
bool cmSystemTools::IsNOTFOUND(const char* val)
{
Bill Hoffman's avatar
Bill Hoffman committed
324
325
326
327
  int len = strlen(val);
  const char* notfound = "-NOTFOUND";
  const int lenNotFound = 9;
  if(len < lenNotFound-1)
328
    {
Bill Hoffman's avatar
Bill Hoffman committed
329
330
331
332
333
    return false;
    }
  if(len == lenNotFound-1)
    {
    return ( strcmp(val, "NOTFOUND") == 0);
334
    }
Bill Hoffman's avatar
Bill Hoffman committed
335
  return ((strncmp((val + (len - lenNotFound)), notfound, lenNotFound) == 0));
Brad King's avatar
Brad King committed
336
}
337
338


Brad King's avatar
Brad King committed
339
bool cmSystemTools::IsOff(const char* val)
340
{
Brad King's avatar
Brad King committed
341
  if (!val || strlen(val) == 0)
342
    {
Brad King's avatar
Brad King committed
343
    return true;
344
    }
Brad King's avatar
Brad King committed
345
  std::basic_string<char> v = val;
346
  
Brad King's avatar
Brad King committed
347
348
  for(std::basic_string<char>::iterator c = v.begin();
      c != v.end(); c++)
349
    {
Brad King's avatar
Brad King committed
350
    *c = toupper(*c);
351
    }
Brad King's avatar
Brad King committed
352
353
  return (v == "OFF" || v == "0" || v == "NO" || v == "FALSE" || 
          v == "N" || cmSystemTools::IsNOTFOUND(v.c_str()) || v == "IGNORE");
354
355
}

356
std::vector<cmStdString> cmSystemTools::ParseArguments(const char* command)
357
{
358
  std::vector<cmStdString> args;
359
  std::string arg;
360

Andy Cedilnik's avatar
Andy Cedilnik committed
361
362
363
364
  bool win_path = false;

  if ( command[0] != '/' && command[1] == ':' && command[2] == '\\' ||
       command[0] == '\"' && command[1] != '/' && command[2] == ':' && command[3] == '\\' || 
Andy Cedilnik's avatar
Andy Cedilnik committed
365
       command[0] == '\'' && command[1] != '/' && command[2] == ':' && command[3] == '\\' || 
Andy Cedilnik's avatar
Andy Cedilnik committed
366
367
368
369
       command[0] == '\\' && command[1] == '\\')
    {
    win_path = true;
    }
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
  // 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
385
386
        arg.append(1, *c);
        ++c;
387
388
389
390
391
392
393
        }
      if(*c)
        {
        ++c;
        }
      args.push_back(arg);
      }
Andy Cedilnik's avatar
Andy Cedilnik committed
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
    else if(*c == '\'')
      {
      // Parse a quoted argument.
      ++c;
      while(*c && *c != '\'')
        {
        arg.append(1, *c);
        ++c;
        }
      if(*c)
        {
        ++c;
        }
      args.push_back(arg);
      }
409
410
411
412
413
    else if(*c)
      {
      // Parse an unquoted argument.
      while(*c && *c != ' ' && *c != '\t')
        {
Andy Cedilnik's avatar
Andy Cedilnik committed
414
        if(*c == '\\' && !win_path)
415
416
417
418
419
420
421
422
423
424
425
426
427
          {
          ++c;
          if(*c)
            {
            arg.append(1, *c);
            ++c;
            }
          }
        else
          {
          arg.append(1, *c);
          ++c;
          }
428
429
430
431
432
        }
      args.push_back(arg);
      }
    }
  
433
434
435
436
437
438
439
440
441
  return args;
}

bool cmSystemTools::RunSingleCommand(
  const char* command, 
  std::string* output,
  int *retVal, 
  const char* dir,
  bool verbose,
442
  double timeout)
443
444
{
  if(s_DisableRunCommandOutput)
445
    {
446
    verbose = false;
447
    }
448

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

  if(args.size() < 1)
452
    {
453
    return false;
454
    }
455
456
  
  std::vector<const char*> argv;
457
458
459
460
461
462
  for(std::vector<cmStdString>::const_iterator a = args.begin();
      a != args.end(); ++a)
    {
    argv.push_back(a->c_str());
    }
  argv.push_back(0);
463
464
465
466
  if ( output )
    {
    *output = "";
    }
467

468
469
470
  cmsysProcess* cp = cmsysProcess_New();
  cmsysProcess_SetCommand(cp, &*argv.begin());
  cmsysProcess_SetWorkingDirectory(cp, dir);
471
472
473
474
  if(cmSystemTools::GetRunCommandHideConsole())
    {
    cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
    }
475
476
477
  cmsysProcess_SetTimeout(cp, timeout);
  cmsysProcess_Execute(cp);
  
478
  std::vector<char> tempOutput;
479
480
  char* data;
  int length;
481
482
  if ( output || verbose )
    {
483
  while(cmsysProcess_WaitForData(cp, &data, &length, 0))
484
    {
485
486
487
488
489
490
491
492
493
494
495
496
497
    if(output || verbose)
      {
      // 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)
        {
        if(data[i] == '\0')
          {
          data[i] = ' ';
          }
        }
      }
498
499
    if ( output )
      {
500
      tempOutput.insert(tempOutput.end(), data, data+length);
501
502
503
      }
    if(verbose)
      {
504
      cmSystemTools::Stdout(data, length);
505
506
      }
    }
507
    }
508
509
  
  cmsysProcess_WaitForExit(cp, 0);
510
  if ( output && tempOutput.begin() != tempOutput.end())
511
512
513
    {
    output->append(&*tempOutput.begin(), tempOutput.size());
    }
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
  
  bool result = true;
  if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exited)
    {
    if ( retVal )
      {
      *retVal = cmsysProcess_GetExitValue(cp);
      }
    else
      {
      if ( cmsysProcess_GetExitValue(cp) !=  0 )
        {
        result = false;
        }
      }
    }
530
531
  else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exception)
    {
532
533
534
535
536
    const char* exception_str = cmsysProcess_GetExceptionString(cp);
    if ( verbose )
      {
      std::cerr << exception_str << std::endl;
      }
537
538
539
540
    if ( output )
      {
      output->append(exception_str, strlen(exception_str));
      }
541
542
    result = false;
    }
543
  else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Error)
544
    {
545
546
547
548
549
    const char* error_str = cmsysProcess_GetErrorString(cp);
    if ( verbose )
      {
      std::cerr << error_str << std::endl;
      }
550
551
552
553
    if ( output )
      {
      output->append(error_str, strlen(error_str));
      }
554
555
    result = false;
    }
556
557
  else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Expired)
    {
558
559
560
561
562
    const char* error_str = "Process terminated due to timeout\n";
    if ( verbose )
      {
      std::cerr << error_str << std::endl;
      }
563
564
565
566
    if ( output )
      {
      output->append(error_str, strlen(error_str));
      }
567
568
    result = false;
    }
569
570
571
572
  
  cmsysProcess_Delete(cp);
  return result;
}
Brad King's avatar
Brad King committed
573
574
575
576
577
bool cmSystemTools::RunCommand(const char* command, 
                               std::string& output,
                               const char* dir,
                               bool verbose,
                               int timeout)
578
{
Brad King's avatar
Brad King committed
579
580
581
  int dummy;
  return cmSystemTools::RunCommand(command, output, dummy, 
                                   dir, verbose, timeout);
582
583
}

584
585
586
587
588
589
590
591
592
#if defined(WIN32) && !defined(__CYGWIN__)
#include "cmWin32ProcessExecution.h"
// use this for shell commands like echo and dir
bool RunCommandViaWin32(const char* command,
                        const char* dir,
                        std::string& output,
                        int& retVal,
                        bool verbose,
                        int timeout)
593
{
594
595
596
597
598
599
600
601
#if defined(__BORLANDC__)
  return cmWin32ProcessExecution::BorlandRunCommand(command, dir, output, 
                                                    retVal, 
                                                    verbose, timeout, 
                                                    cmSystemTools::GetRunCommandHideConsole());
#else // Visual studio
  ::SetLastError(ERROR_SUCCESS);
  if ( ! command )
Ken Martin's avatar
Ken Martin committed
602
    {
603
604
605
606
607
608
609
    cmSystemTools::Error("No command specified");
    return false;
    }
  cmWin32ProcessExecution resProc;
  if(cmSystemTools::GetRunCommandHideConsole())
    {
    resProc.SetHideWindows(true);
Ken Martin's avatar
Ken Martin committed
610
    }
611
  
612
  if ( cmSystemTools::GetWindows9xComspecSubstitute() )
613
    {
614
615
616
617
    resProc.SetConsoleSpawn(cmSystemTools::GetWindows9xComspecSubstitute() );
    }
  if ( !resProc.StartProcess(command, dir, verbose) )
    {
618
619
620
621
622
    output = resProc.GetOutput();
    if(verbose)
      {
      cmSystemTools::Stdout(output.c_str());
      }
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
    return false;
    }
  resProc.Wait(timeout);
  output = resProc.GetOutput();
  retVal = resProc.GetExitValue();
  return true;
#endif
}

// use this for shell commands like echo and dir
bool RunCommandViaSystem(const char* command,
                         const char* dir,
                         std::string& output,
                         int& retVal,
                         bool verbose)
{  
  std::cout << "@@ " << command << std::endl;

  std::string commandInDir;
  if(dir)
    {
    commandInDir = "cd ";
    commandInDir += cmSystemTools::ConvertToOutputPath(dir);
    commandInDir += " && ";
    commandInDir += command;
    }
  else
    {
    commandInDir = command;
    }
  command = commandInDir.c_str();
  std::string commandToFile = command;
  commandToFile += " > ";
  std::string tempFile;
  tempFile += _tempnam(0, "cmake");

  commandToFile += tempFile;
  retVal = system(commandToFile.c_str());
  std::ifstream fin(tempFile.c_str());
  if(!fin)
    {
    if(verbose)
665
      {
666
667
668
669
670
671
      std::string errormsg = "RunCommand produced no output: command: \"";
      errormsg += command;
      errormsg += "\"";
      errormsg += "\nOutput file: ";
      errormsg += tempFile;
      cmSystemTools::Error(errormsg.c_str());
672
      }
673
674
675
676
677
678
679
680
681
682
    fin.close();
    cmSystemTools::RemoveFile(tempFile.c_str());
    return false;
    }
  bool multiLine = false;
  std::string line;
  while(cmSystemTools::GetLineFromStream(fin, line))
    {
    output += line;
    if(multiLine)
683
      {
684
      output += "\n";
685
      }
686
    multiLine = true;
687
    }
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
  fin.close();
  cmSystemTools::RemoveFile(tempFile.c_str());
  return true;
}

#else // We have popen

bool RunCommandViaPopen(const char* command,
                        const char* dir,
                        std::string& output,
                        int& retVal,
                        bool verbose,
                        int /*timeout*/)
{
  // if only popen worked on windows.....
  std::string commandInDir;
  if(dir)
705
    {
706
707
708
709
    commandInDir = "cd \"";
    commandInDir += dir;
    commandInDir += "\" && ";
    commandInDir += command;
710
    }
711
712
713
714
715
716
717
718
719
720
  else
    {
    commandInDir = command;
    }
  commandInDir += " 2>&1";
  command = commandInDir.c_str();
  const int BUFFER_SIZE = 4096;
  char buffer[BUFFER_SIZE];
  if(verbose)
    {
721
722
723
    cmSystemTools::Stdout("running ");
    cmSystemTools::Stdout(command);
    cmSystemTools::Stdout("\n");
724
725
726
727
728
    }
  fflush(stdout);
  fflush(stderr);
  FILE* cpipe = popen(command, "r");
  if(!cpipe)
Ken Martin's avatar
Ken Martin committed
729
    {
Brad King's avatar
Brad King committed
730
    return false;
Ken Martin's avatar
Ken Martin committed
731
    }
732
733
  fgets(buffer, BUFFER_SIZE, cpipe);
  while(!feof(cpipe))
734
    {
735
    if(verbose)
Brad King's avatar
Brad King committed
736
      {
737
      cmSystemTools::Stdout(buffer);
Brad King's avatar
Brad King committed
738
      }
739
740
    output += buffer;
    fgets(buffer, BUFFER_SIZE, cpipe);
741
    }
742
743
744

  retVal = pclose(cpipe);
  if (WIFEXITED(retVal))
745
    {
746
747
    retVal = WEXITSTATUS(retVal);
    return true;
748
    }
749
  if (WIFSIGNALED(retVal))
750
    {
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
    retVal = WTERMSIG(retVal);
    cmOStringStream error;
    error << "\nProcess terminated due to ";
    switch (retVal)
      {
#ifdef SIGKILL
      case SIGKILL:
        error << "SIGKILL";
        break;
#endif
#ifdef SIGFPE
      case SIGFPE:
        error << "SIGFPE";
        break;
#endif
#ifdef SIGBUS
      case SIGBUS:
        error << "SIGBUS";
        break;
#endif
#ifdef SIGSEGV
      case SIGSEGV:
        error << "SIGSEGV";
        break;
#endif
      default:
        error << "signal " << retVal;
        break;
      }
    output += error.str();
    }
  return false;
}

#endif  // endif WIN32 not CYGWIN


// run a command unix uses popen (easy)
// windows uses system and ShortPath
bool cmSystemTools::RunCommand(const char* command, 
                               std::string& output,
                               int &retVal, 
                               const char* dir,
                               bool verbose,
                               int timeout)
{
  if(s_DisableRunCommandOutput)
    {
    verbose = false;
800
801
    }
  
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
#if defined(WIN32) && !defined(__CYGWIN__)
  // if the command does not start with a quote, then
  // try to find the program, and if the program can not be
  // found use system to run the command as it must be a built in
  // shell command like echo or dir
  int count = 0;
  if(command[0] == '\"')
    {
    // count the number of quotes
    for(const char* s = command; *s != 0; ++s)
      {
      if(*s == '\"')
        {
        count++;
        if(count > 2)
          {
          break;
          }
        }      
      }
    // if there are more than two double quotes use 
    // GetShortPathName, the cmd.exe program in windows which
    // is used by system fails to execute if there are more than
    // one set of quotes in the arguments
    if(count > 2)
      {
      cmsys::RegularExpression quoted("^\"([^\"]*)\"[ \t](.*)");
      if(quoted.find(command))
        {
        std::string shortCmd;
        std::string cmd = quoted.match(1);
        std::string args = quoted.match(2);
        if(! cmSystemTools::FileExists(cmd.c_str()) )
          {
          shortCmd = cmd;
          }
        else if(!cmSystemTools::GetShortPath(cmd.c_str(), shortCmd))
          {
         cmSystemTools::Error("GetShortPath failed for " , cmd.c_str());
          return false;
          }
        shortCmd += " ";
        shortCmd += args;

        //return RunCommandViaSystem(shortCmd.c_str(), dir, 
        //                           output, retVal, verbose);
        //return WindowsRunCommand(shortCmd.c_str(), dir, 
        //output, retVal, verbose);
        return RunCommandViaWin32(shortCmd.c_str(), dir, 
                                  output, retVal, verbose, timeout);
        }
      else
        {
        cmSystemTools::Error("Could not parse command line with quotes ", 
                             command);
        }
      }
    }
  // if there is only one set of quotes or no quotes then just run the command
  //return RunCommandViaSystem(command, dir, output, retVal, verbose);
  //return WindowsRunCommand(command, dir, output, retVal, verbose);
  return ::RunCommandViaWin32(command, dir, output, retVal, verbose, timeout);
#else
  return ::RunCommandViaPopen(command, dir, output, retVal, verbose, timeout);
#endif
867
868
}

Brad King's avatar
Brad King committed
869
870
871
bool cmSystemTools::DoesFileExistWithExtensions(
  const char* name,
  const std::vector<std::string>& headerExts)
872
{
Brad King's avatar
Brad King committed
873
874
875
876
  std::string hname;

  for( std::vector<std::string>::const_iterator ext = headerExts.begin();
       ext != headerExts.end(); ++ext )
877
    {
Brad King's avatar
Brad King committed
878
879
880
881
882
883
884
    hname = name;
    hname += ".";
    hname += *ext;
    if(cmSystemTools::FileExists(hname.c_str()))
      {
      return true;
      }
885
    }
Brad King's avatar
Brad King committed
886
  return false;
887
888
}

Brad King's avatar
Brad King committed
889
bool cmSystemTools::cmCopyFile(const char* source, const char* destination)
890
{
891
  return Superclass::CopyFileAlways(source, destination);
892
893
894
895
896
}

bool cmSystemTools::CopyFileIfDifferent(const char* source, 
  const char* destination)
{
897
  return Superclass::CopyFileIfDifferent(source, destination);
898
}
899

Ken Martin's avatar
Ken Martin committed
900
901
902
void cmSystemTools::Glob(const char *directory, const char *regexp,
                         std::vector<std::string>& files)
{
Brad King's avatar
Brad King committed
903
  cmsys::Directory d;
904
  cmsys::RegularExpression reg(regexp);
Ken Martin's avatar
Ken Martin committed
905
906
907
  
  if (d.Load(directory))
    {
908
    size_t numf;
909
        unsigned int i;
Ken Martin's avatar
Ken Martin committed
910
911
912
913
914
915
916
917
918
919
920
921
    numf = d.GetNumberOfFiles();
    for (i = 0; i < numf; i++)
      {
      std::string fname = d.GetFile(i);
      if (reg.find(fname))
        {
        files.push_back(fname);
        }
      }
    }
}

922
923
924
925
926

void cmSystemTools::GlobDirs(const char *fullPath,
                             std::vector<std::string>& files)
{
  std::string path = fullPath;
Bill Hoffman's avatar
Bill Hoffman committed
927
  std::string::size_type pos = path.find("/*");
928
929
930
931
932
933
934
935
  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
936
  cmsys::Directory d;
937
938
  if (d.Load(startPath.c_str()))
    {
Bill Hoffman's avatar
Bill Hoffman committed
939
    for (unsigned int i = 0; i < d.GetNumberOfFiles(); ++i)
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
      {
      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);
          }
        }
      }
    }
}
956
957


958
959
void cmSystemTools::ExpandList(std::vector<std::string> const& arguments, 
                               std::vector<std::string>& newargs)
960
961
962
963
{
  std::vector<std::string>::const_iterator i;
  for(i = arguments.begin();i != arguments.end(); ++i)
    {
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
    cmSystemTools::ExpandListArgument(*i, newargs);
    }
}

void cmSystemTools::ExpandListArgument(const std::string& arg,
                                       std::vector<std::string>& newargs)
{
  // If argument is empty, it is an empty list.
  if(arg.length() == 0)
    {
    return;
    }
  // if there are no ; in the name then just copy the current string
  if(arg.find(';') == std::string::npos)
    {
    newargs.push_back(arg);
980
    return;
981
    }
982
  std::vector<char> newArgVec;
983
984
985
  // Break the string at non-escaped semicolons not nested in [].
  int squareNesting = 0;
  for(const char* c = arg.c_str(); *c; ++c)
986
    {
987
    switch(*c)
988
      {
989
      case '\\':
990
        {
991
992
993
994
        // We only want to allow escaping of semicolons.  Other
        // escapes should not be processed here.
        ++c;
        if(*c == ';')
995
          {
996
          newArgVec.push_back(*c);
997
          }
998
        else
999
          {
1000
          newArgVec.push_back('\\');