PageRenderTime 272ms CodeModel.GetById 120ms app.highlight 134ms RepoModel.GetById 2ms app.codeStats 0ms

/cmake-2.8.9-rc2/Source/cmFileCommand.cxx

#
C++ | 3180 lines | 2713 code | 265 blank | 202 comment | 646 complexity | 2fa064d8b4c9c9970686f6903f849057 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*============================================================================
   2  CMake - Cross Platform Makefile Generator
   3  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
   4
   5  Distributed under the OSI-approved BSD License (the "License");
   6  see accompanying file Copyright.txt for details.
   7
   8  This software is distributed WITHOUT ANY WARRANTY; without even the
   9  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10  See the License for more information.
  11============================================================================*/
  12#include "cmFileCommand.h"
  13#include "cmake.h"
  14#include "cmHexFileConverter.h"
  15#include "cmInstallType.h"
  16#include "cmFileTimeComparison.h"
  17#include "cmCryptoHash.h"
  18
  19#if defined(CMAKE_BUILD_WITH_CMAKE)
  20#include "cm_curl.h"
  21#endif
  22
  23#undef GetCurrentDirectory
  24#include <sys/types.h>
  25#include <sys/stat.h>
  26
  27#include <cmsys/auto_ptr.hxx>
  28#include <cmsys/Directory.hxx>
  29#include <cmsys/Glob.hxx>
  30#include <cmsys/RegularExpression.hxx>
  31
  32// Table of permissions flags.
  33#if defined(_WIN32) && !defined(__CYGWIN__)
  34static mode_t mode_owner_read = S_IREAD;
  35static mode_t mode_owner_write = S_IWRITE;
  36static mode_t mode_owner_execute = S_IEXEC;
  37static mode_t mode_group_read = 0;
  38static mode_t mode_group_write = 0;
  39static mode_t mode_group_execute = 0;
  40static mode_t mode_world_read = 0;
  41static mode_t mode_world_write = 0;
  42static mode_t mode_world_execute = 0;
  43static mode_t mode_setuid = 0;
  44static mode_t mode_setgid = 0;
  45#else
  46static mode_t mode_owner_read = S_IRUSR;
  47static mode_t mode_owner_write = S_IWUSR;
  48static mode_t mode_owner_execute = S_IXUSR;
  49static mode_t mode_group_read = S_IRGRP;
  50static mode_t mode_group_write = S_IWGRP;
  51static mode_t mode_group_execute = S_IXGRP;
  52static mode_t mode_world_read = S_IROTH;
  53static mode_t mode_world_write = S_IWOTH;
  54static mode_t mode_world_execute = S_IXOTH;
  55static mode_t mode_setuid = S_ISUID;
  56static mode_t mode_setgid = S_ISGID;
  57#endif
  58
  59// cmLibraryCommand
  60bool cmFileCommand
  61::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
  62{
  63  if(args.size() < 2 )
  64    {
  65    this->SetError("must be called with at least two arguments.");
  66    return false;
  67    }
  68  std::string subCommand = args[0];
  69  if ( subCommand == "WRITE" )
  70    {
  71    return this->HandleWriteCommand(args, false);
  72    }
  73  else if ( subCommand == "APPEND" )
  74    {
  75    return this->HandleWriteCommand(args, true);
  76    }
  77  else if ( subCommand == "DOWNLOAD" )
  78    {
  79    return this->HandleDownloadCommand(args);
  80    }
  81  else if ( subCommand == "UPLOAD" )
  82    {
  83    return this->HandleUploadCommand(args);
  84    }
  85  else if ( subCommand == "READ" )
  86    {
  87    return this->HandleReadCommand(args);
  88    }
  89  else if ( subCommand == "MD5" ||
  90            subCommand == "SHA1" ||
  91            subCommand == "SHA224" ||
  92            subCommand == "SHA256" ||
  93            subCommand == "SHA384" ||
  94            subCommand == "SHA512" )
  95    {
  96    return this->HandleHashCommand(args);
  97    }
  98  else if ( subCommand == "STRINGS" )
  99    {
 100    return this->HandleStringsCommand(args);
 101    }
 102  else if ( subCommand == "GLOB" )
 103    {
 104    return this->HandleGlobCommand(args, false);
 105    }
 106  else if ( subCommand == "GLOB_RECURSE" )
 107    {
 108    return this->HandleGlobCommand(args, true);
 109    }
 110  else if ( subCommand == "MAKE_DIRECTORY" )
 111    {
 112    return this->HandleMakeDirectoryCommand(args);
 113    }
 114  else if ( subCommand == "RENAME" )
 115    {
 116    return this->HandleRename(args);
 117    }
 118  else if ( subCommand == "REMOVE" )
 119    {
 120    return this->HandleRemove(args, false);
 121    }
 122  else if ( subCommand == "REMOVE_RECURSE" )
 123    {
 124    return this->HandleRemove(args, true);
 125    }
 126  else if ( subCommand == "COPY" )
 127    {
 128    return this->HandleCopyCommand(args);
 129    }
 130  else if ( subCommand == "INSTALL" )
 131    {
 132    return this->HandleInstallCommand(args);
 133    }
 134  else if ( subCommand == "DIFFERENT" )
 135    {
 136    return this->HandleDifferentCommand(args);
 137    }
 138  else if ( subCommand == "RPATH_CHANGE" || subCommand == "CHRPATH" )
 139    {
 140    return this->HandleRPathChangeCommand(args);
 141    }
 142  else if ( subCommand == "RPATH_CHECK" )
 143    {
 144    return this->HandleRPathCheckCommand(args);
 145    }
 146  else if ( subCommand == "RPATH_REMOVE" )
 147    {
 148    return this->HandleRPathRemoveCommand(args);
 149    }
 150  else if ( subCommand == "RELATIVE_PATH" )
 151    {
 152    return this->HandleRelativePathCommand(args);
 153    }
 154  else if ( subCommand == "TO_CMAKE_PATH" )
 155    {
 156    return this->HandleCMakePathCommand(args, false);
 157    }
 158  else if ( subCommand == "TO_NATIVE_PATH" )
 159    {
 160    return this->HandleCMakePathCommand(args, true);
 161    }
 162
 163  std::string e = "does not recognize sub-command "+subCommand;
 164  this->SetError(e.c_str());
 165  return false;
 166}
 167
 168//----------------------------------------------------------------------------
 169bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args,
 170  bool append)
 171{
 172  std::string message;
 173  std::vector<std::string>::const_iterator i = args.begin();
 174
 175  i++; // Get rid of subcommand
 176
 177  std::string fileName = *i;
 178  if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
 179    {
 180    fileName = this->Makefile->GetCurrentDirectory();
 181    fileName += "/" + *i;
 182    }
 183
 184  i++;
 185
 186  for(;i != args.end(); ++i)
 187    {
 188    message += *i;
 189    }
 190  if ( !this->Makefile->CanIWriteThisFile(fileName.c_str()) )
 191    {
 192    std::string e
 193      = "attempted to write a file: " + fileName +
 194      " into a source directory.";
 195    this->SetError(e.c_str());
 196    cmSystemTools::SetFatalErrorOccured();
 197    return false;
 198    }
 199  std::string dir = cmSystemTools::GetFilenamePath(fileName);
 200  cmSystemTools::MakeDirectory(dir.c_str());
 201
 202  mode_t mode = 0;
 203
 204  // Set permissions to writable
 205  if ( cmSystemTools::GetPermissions(fileName.c_str(), mode) )
 206    {
 207    cmSystemTools::SetPermissions(fileName.c_str(),
 208#if defined( _MSC_VER ) || defined( __MINGW32__ )
 209      mode | S_IWRITE
 210#elif defined( __BORLANDC__ )
 211      mode | S_IWUSR
 212#else
 213      mode | S_IWUSR | S_IWGRP
 214#endif
 215    );
 216    }
 217  // If GetPermissions fails, pretend like it is ok. File open will fail if
 218  // the file is not writable
 219  std::ofstream file(fileName.c_str(), append?std::ios::app: std::ios::out);
 220  if ( !file )
 221    {
 222    std::string error = "Internal CMake error when trying to open file: ";
 223    error += fileName.c_str();
 224    error += " for writing.";
 225    this->SetError(error.c_str());
 226    return false;
 227    }
 228  file << message;
 229  file.close();
 230  if(mode)
 231    {
 232    cmSystemTools::SetPermissions(fileName.c_str(), mode);
 233    }
 234  return true;
 235}
 236
 237//----------------------------------------------------------------------------
 238bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args)
 239{
 240  if ( args.size() < 3 )
 241    {
 242    this->SetError("READ must be called with at least two additional "
 243                   "arguments");
 244    return false;
 245    }
 246
 247  cmCommandArgumentsHelper argHelper;
 248  cmCommandArgumentGroup group;
 249
 250  cmCAString readArg    (&argHelper, "READ");
 251  cmCAString fileNameArg    (&argHelper, 0);
 252  cmCAString resultArg      (&argHelper, 0);
 253
 254  cmCAString offsetArg      (&argHelper, "OFFSET", &group);
 255  cmCAString limitArg       (&argHelper, "LIMIT", &group);
 256  cmCAEnabler hexOutputArg  (&argHelper, "HEX", &group);
 257  readArg.Follows(0);
 258  fileNameArg.Follows(&readArg);
 259  resultArg.Follows(&fileNameArg);
 260  group.Follows(&resultArg);
 261  argHelper.Parse(&args, 0);
 262
 263  std::string fileName = fileNameArg.GetString();
 264  if ( !cmsys::SystemTools::FileIsFullPath(fileName.c_str()) )
 265    {
 266    fileName = this->Makefile->GetCurrentDirectory();
 267    fileName += "/" + fileNameArg.GetString();
 268    }
 269
 270  std::string variable = resultArg.GetString();
 271
 272  // Open the specified file.
 273#if defined(_WIN32) || defined(__CYGWIN__)
 274  std::ifstream file(fileName.c_str(), std::ios::in | 
 275               (hexOutputArg.IsEnabled() ? std::ios::binary : std::ios::in));
 276#else
 277  std::ifstream file(fileName.c_str(), std::ios::in);
 278#endif
 279
 280  if ( !file )
 281    {
 282    std::string error = "Internal CMake error when trying to open file: ";
 283    error += fileName.c_str();
 284    error += " for reading.";
 285    this->SetError(error.c_str());
 286    return false;
 287    }
 288
 289  // is there a limit?
 290  long sizeLimit = -1;
 291  if (limitArg.GetString().size() > 0)
 292    {
 293    sizeLimit = atoi(limitArg.GetCString());
 294    }
 295
 296  // is there an offset?
 297  long offset = 0;
 298  if (offsetArg.GetString().size() > 0)
 299    {
 300    offset = atoi(offsetArg.GetCString());
 301    }
 302
 303  file.seekg(offset, std::ios::beg); // explicit ios::beg for IBM VisualAge 6
 304
 305  std::string output;
 306
 307  if (hexOutputArg.IsEnabled())
 308    {
 309    // Convert part of the file into hex code
 310    char c;
 311    while((sizeLimit != 0) && (file.get(c)))
 312      {
 313      char hex[4];
 314      sprintf(hex, "%.2x", c&0xff);
 315      output += hex;
 316      if (sizeLimit > 0)
 317        {
 318        sizeLimit--;
 319        }
 320      }
 321    }
 322  else
 323    {
 324    std::string line;
 325    bool has_newline = false;
 326    while (sizeLimit != 0 &&
 327          cmSystemTools::GetLineFromStream(file, line, &has_newline,
 328                                            sizeLimit) )
 329      {
 330      if (sizeLimit > 0)
 331        {
 332        sizeLimit = sizeLimit - static_cast<long>(line.size());
 333        if (has_newline)
 334          {
 335          sizeLimit--;
 336          }
 337        if (sizeLimit < 0)
 338          {
 339          sizeLimit = 0;
 340          }
 341        }
 342      output += line;
 343      if ( has_newline )
 344        {
 345        output += "\n";
 346        }
 347      }
 348    }
 349  this->Makefile->AddDefinition(variable.c_str(), output.c_str());
 350  return true;
 351}
 352
 353//----------------------------------------------------------------------------
 354bool cmFileCommand::HandleHashCommand(std::vector<std::string> const& args)
 355{
 356#if defined(CMAKE_BUILD_WITH_CMAKE)
 357  if(args.size() != 3)
 358    {
 359    cmOStringStream e;
 360    e << args[0] << " requires a file name and output variable";
 361    this->SetError(e.str().c_str());
 362    return false;
 363    }
 364
 365  cmsys::auto_ptr<cmCryptoHash> hash(cmCryptoHash::New(args[0].c_str()));
 366  if(hash.get())
 367    {
 368    std::string out = hash->HashFile(args[1].c_str());
 369    if(!out.empty())
 370      {
 371      this->Makefile->AddDefinition(args[2].c_str(), out.c_str());
 372      return true;
 373      }
 374    cmOStringStream e;
 375    e << args[0] << " failed to read file \"" << args[1] << "\": "
 376      << cmSystemTools::GetLastSystemError();
 377    this->SetError(e.str().c_str());
 378    }
 379  return false;
 380#else
 381  cmOStringStream e;
 382  e << args[0] << " not available during bootstrap";
 383  this->SetError(e.str().c_str());
 384  return false;
 385#endif
 386}
 387
 388//----------------------------------------------------------------------------
 389bool cmFileCommand::HandleStringsCommand(std::vector<std::string> const& args)
 390{
 391  if(args.size() < 3)
 392    {
 393    this->SetError("STRINGS requires a file name and output variable");
 394    return false;
 395    }
 396
 397  // Get the file to read.
 398  std::string fileName = args[1];
 399  if(!cmsys::SystemTools::FileIsFullPath(fileName.c_str()))
 400    {
 401    fileName = this->Makefile->GetCurrentDirectory();
 402    fileName += "/" + args[1];
 403    }
 404
 405  // Get the variable in which to store the results.
 406  std::string outVar = args[2];
 407
 408  // Parse the options.
 409  enum { arg_none,
 410         arg_limit_input,
 411         arg_limit_output,
 412         arg_limit_count,
 413         arg_length_minimum,
 414         arg_length_maximum,
 415         arg__maximum,
 416         arg_regex };
 417  unsigned int minlen = 0;
 418  unsigned int maxlen = 0;
 419  int limit_input = -1;
 420  int limit_output = -1;
 421  unsigned int limit_count = 0;
 422  cmsys::RegularExpression regex;
 423  bool have_regex = false;
 424  bool newline_consume = false;
 425  bool hex_conversion_enabled = true;
 426  int arg_mode = arg_none;
 427  for(unsigned int i=3; i < args.size(); ++i)
 428    {
 429    if(args[i] == "LIMIT_INPUT")
 430      {
 431      arg_mode = arg_limit_input;
 432      }
 433    else if(args[i] == "LIMIT_OUTPUT")
 434      {
 435      arg_mode = arg_limit_output;
 436      }
 437    else if(args[i] == "LIMIT_COUNT")
 438      {
 439      arg_mode = arg_limit_count;
 440      }
 441    else if(args[i] == "LENGTH_MINIMUM")
 442      {
 443      arg_mode = arg_length_minimum;
 444      }
 445    else if(args[i] == "LENGTH_MAXIMUM")
 446      {
 447      arg_mode = arg_length_maximum;
 448      }
 449    else if(args[i] == "REGEX")
 450      {
 451      arg_mode = arg_regex;
 452      }
 453    else if(args[i] == "NEWLINE_CONSUME")
 454      {
 455      newline_consume = true;
 456      arg_mode = arg_none;
 457      }
 458    else if(args[i] == "NO_HEX_CONVERSION")
 459      {
 460      hex_conversion_enabled = false;
 461      arg_mode = arg_none;
 462      }
 463    else if(arg_mode == arg_limit_input)
 464      {
 465      if(sscanf(args[i].c_str(), "%d", &limit_input) != 1 ||
 466         limit_input < 0)
 467        {
 468        cmOStringStream e;
 469        e << "STRINGS option LIMIT_INPUT value \""
 470          << args[i] << "\" is not an unsigned integer.";
 471        this->SetError(e.str().c_str());
 472        return false;
 473        }
 474      arg_mode = arg_none;
 475      }
 476    else if(arg_mode == arg_limit_output)
 477      {
 478      if(sscanf(args[i].c_str(), "%d", &limit_output) != 1 ||
 479         limit_output < 0)
 480        {
 481        cmOStringStream e;
 482        e << "STRINGS option LIMIT_OUTPUT value \""
 483          << args[i] << "\" is not an unsigned integer.";
 484        this->SetError(e.str().c_str());
 485        return false;
 486        }
 487      arg_mode = arg_none;
 488      }
 489    else if(arg_mode == arg_limit_count)
 490      {
 491      int count;
 492      if(sscanf(args[i].c_str(), "%d", &count) != 1 || count < 0)
 493        {
 494        cmOStringStream e;
 495        e << "STRINGS option LIMIT_COUNT value \""
 496          << args[i] << "\" is not an unsigned integer.";
 497        this->SetError(e.str().c_str());
 498        return false;
 499        }
 500      limit_count = count;
 501      arg_mode = arg_none;
 502      }
 503    else if(arg_mode == arg_length_minimum)
 504      {
 505      int len;
 506      if(sscanf(args[i].c_str(), "%d", &len) != 1 || len < 0)
 507        {
 508        cmOStringStream e;
 509        e << "STRINGS option LENGTH_MINIMUM value \""
 510          << args[i] << "\" is not an unsigned integer.";
 511        this->SetError(e.str().c_str());
 512        return false;
 513        }
 514      minlen = len;
 515      arg_mode = arg_none;
 516      }
 517    else if(arg_mode == arg_length_maximum)
 518      {
 519      int len;
 520      if(sscanf(args[i].c_str(), "%d", &len) != 1 || len < 0)
 521        {
 522        cmOStringStream e;
 523        e << "STRINGS option LENGTH_MAXIMUM value \""
 524          << args[i] << "\" is not an unsigned integer.";
 525        this->SetError(e.str().c_str());
 526        return false;
 527        }
 528      maxlen = len;
 529      arg_mode = arg_none;
 530      }
 531    else if(arg_mode == arg_regex)
 532      {
 533      if(!regex.compile(args[i].c_str()))
 534        {
 535        cmOStringStream e;
 536        e << "STRINGS option REGEX value \""
 537          << args[i] << "\" could not be compiled.";
 538        this->SetError(e.str().c_str());
 539        return false;
 540        }
 541      have_regex = true;
 542      arg_mode = arg_none;
 543      }
 544    else
 545      {
 546      cmOStringStream e;
 547      e << "STRINGS given unknown argument \""
 548        << args[i] << "\"";
 549      this->SetError(e.str().c_str());
 550      return false;
 551      }
 552    }
 553
 554  if (hex_conversion_enabled)
 555    {
 556    // TODO: should work without temp file, but just on a memory buffer
 557    std::string binaryFileName = this->Makefile->GetCurrentOutputDirectory();
 558    binaryFileName += cmake::GetCMakeFilesDirectory();
 559    binaryFileName += "/FileCommandStringsBinaryFile";
 560    if(cmHexFileConverter::TryConvert(fileName.c_str(),binaryFileName.c_str()))
 561      {
 562      fileName = binaryFileName;
 563      }
 564    }
 565
 566  // Open the specified file.
 567#if defined(_WIN32) || defined(__CYGWIN__)
 568  std::ifstream fin(fileName.c_str(), std::ios::in | std::ios::binary);
 569#else
 570  std::ifstream fin(fileName.c_str(), std::ios::in);
 571#endif
 572  if(!fin)
 573    {
 574    cmOStringStream e;
 575    e << "STRINGS file \"" << fileName << "\" cannot be read.";
 576    this->SetError(e.str().c_str());
 577    return false;
 578    }
 579
 580  // Parse strings out of the file.
 581  int output_size = 0;
 582  std::vector<std::string> strings;
 583  std::string s;
 584  int c;
 585  while((!limit_count || strings.size() < limit_count) &&
 586        (limit_input < 0 || static_cast<int>(fin.tellg()) < limit_input) &&
 587        (c = fin.get(), fin))
 588    {
 589    if(c == '\n' && !newline_consume)
 590      {
 591      // The current line has been terminated.  Check if the current
 592      // string matches the requirements.  The length may now be as
 593      // low as zero since blank lines are allowed.
 594      if(s.length() >= minlen &&
 595         (!have_regex || regex.find(s.c_str())))
 596        {
 597        output_size += static_cast<int>(s.size()) + 1;
 598        if(limit_output >= 0 && output_size >= limit_output)
 599          {
 600          s = "";
 601          break;
 602          }
 603        strings.push_back(s);
 604        }
 605
 606      // Reset the string to empty.
 607      s = "";
 608      }
 609    else if(c == '\r')
 610      {
 611      // Ignore CR character to make output always have UNIX newlines.
 612      }
 613    else if((c >= 0x20 && c < 0x7F) || c == '\t' ||
 614            (c == '\n' && newline_consume))
 615      {
 616      // This is an ASCII character that may be part of a string.
 617      // Cast added to avoid compiler warning. Cast is ok because
 618      // c is guaranteed to fit in char by the above if...
 619      s += static_cast<char>(c);
 620      }
 621    else
 622      {
 623      // TODO: Support ENCODING option.  See issue #10519.
 624      // A non-string character has been found.  Check if the current
 625      // string matches the requirements.  We require that the length
 626      // be at least one no matter what the user specified.
 627      if(s.length() >= minlen && s.length() >= 1 &&
 628         (!have_regex || regex.find(s.c_str())))
 629        {
 630        output_size += static_cast<int>(s.size()) + 1;
 631        if(limit_output >= 0 && output_size >= limit_output)
 632          {
 633          s = "";
 634          break;
 635          }
 636        strings.push_back(s);
 637        }
 638
 639      // Reset the string to empty.
 640      s = "";
 641      }
 642
 643    // Terminate a string if the maximum length is reached.
 644    if(maxlen > 0 && s.size() == maxlen)
 645      {
 646      if(s.length() >= minlen &&
 647         (!have_regex || regex.find(s.c_str())))
 648        {
 649        output_size += static_cast<int>(s.size()) + 1;
 650        if(limit_output >= 0 && output_size >= limit_output)
 651          {
 652          s = "";
 653          break;
 654          }
 655        strings.push_back(s);
 656        }
 657      s = "";
 658      }
 659    }
 660
 661  // If there is a non-empty current string we have hit the end of the
 662  // input file or the input size limit.  Check if the current string
 663  // matches the requirements.
 664  if((!limit_count || strings.size() < limit_count) &&
 665     !s.empty() && s.length() >= minlen &&
 666     (!have_regex || regex.find(s.c_str())))
 667    {
 668    output_size += static_cast<int>(s.size()) + 1;
 669    if(limit_output < 0 || output_size < limit_output)
 670      {
 671      strings.push_back(s);
 672      }
 673    }
 674
 675  // Encode the result in a CMake list.
 676  const char* sep = "";
 677  std::string output;
 678  for(std::vector<std::string>::const_iterator si = strings.begin();
 679      si != strings.end(); ++si)
 680    {
 681    // Separate the strings in the output to make it a list.
 682    output += sep;
 683    sep = ";";
 684
 685    // Store the string in the output, but escape semicolons to
 686    // make sure it is a list.
 687    std::string const& sr = *si;
 688    for(unsigned int i=0; i < sr.size(); ++i)
 689      {
 690      if(sr[i] == ';')
 691        {
 692        output += '\\';
 693        }
 694      output += sr[i];
 695      }
 696    }
 697
 698  // Save the output in a makefile variable.
 699  this->Makefile->AddDefinition(outVar.c_str(), output.c_str());
 700  return true;
 701}
 702
 703//----------------------------------------------------------------------------
 704bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
 705  bool recurse)
 706{
 707  if ( args.size() < 2 )
 708    {
 709    this->SetError("GLOB requires at least a variable name");
 710    return false;
 711    }
 712
 713  std::vector<std::string>::const_iterator i = args.begin();
 714
 715  i++; // Get rid of subcommand
 716
 717  std::string variable = *i;
 718  i++;
 719  cmsys::Glob g;
 720  g.SetRecurse(recurse);
 721
 722  bool explicitFollowSymlinks = false;
 723  cmPolicies::PolicyStatus status =
 724    this->Makefile->GetPolicyStatus(cmPolicies::CMP0009);
 725  if(recurse)
 726    {
 727    switch(status)
 728      {
 729      case cmPolicies::NEW:
 730        g.RecurseThroughSymlinksOff();
 731        break;
 732      case cmPolicies::OLD:
 733      case cmPolicies::WARN:
 734      case cmPolicies::REQUIRED_IF_USED:
 735      case cmPolicies::REQUIRED_ALWAYS:
 736        g.RecurseThroughSymlinksOn();
 737        break;
 738      }
 739    }
 740
 741  std::string output = "";
 742  bool first = true;
 743  for ( ; i != args.end(); ++i )
 744    {
 745    if ( recurse && (*i == "FOLLOW_SYMLINKS") )
 746      {
 747      explicitFollowSymlinks = true;
 748      g.RecurseThroughSymlinksOn();
 749      ++i;
 750      if ( i == args.end() )
 751        {
 752        this->SetError(
 753          "GLOB_RECURSE requires a glob expression after FOLLOW_SYMLINKS");
 754        return false;
 755        }
 756      }
 757
 758    if ( *i == "RELATIVE" )
 759      {
 760      ++i; // skip RELATIVE
 761      if ( i == args.end() )
 762        {
 763        this->SetError("GLOB requires a directory after the RELATIVE tag");
 764        return false;
 765        }
 766      g.SetRelative(i->c_str());
 767      ++i;
 768      if(i == args.end())
 769        {
 770        this->SetError("GLOB requires a glob expression after the directory");
 771        return false;
 772        }
 773      }
 774
 775    if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
 776      {
 777      std::string expr = this->Makefile->GetCurrentDirectory();
 778      // Handle script mode
 779      if ( expr.size() > 0 )
 780        {
 781        expr += "/" + *i;
 782        g.FindFiles(expr);
 783        }
 784      else
 785        {
 786        g.FindFiles(*i);
 787        }
 788      }
 789    else
 790      {
 791      g.FindFiles(*i);
 792      }
 793
 794    std::vector<std::string>::size_type cc;
 795    std::vector<std::string>& files = g.GetFiles();
 796    for ( cc = 0; cc < files.size(); cc ++ )
 797      {
 798      if ( !first )
 799        {
 800        output += ";";
 801        }
 802      output += files[cc];
 803      first = false;
 804      }
 805    }
 806
 807  if(recurse && !explicitFollowSymlinks)
 808    {
 809    switch (status)
 810      {
 811      case cmPolicies::NEW:
 812        // Correct behavior, yay!
 813        break;
 814      case cmPolicies::OLD:
 815        // Probably not really the expected behavior, but the author explicitly
 816        // asked for the old behavior... no warning.
 817      case cmPolicies::WARN:
 818        // Possibly unexpected old behavior *and* we actually traversed
 819        // symlinks without being explicitly asked to: warn the author.
 820        if(g.GetFollowedSymlinkCount() != 0)
 821          {
 822          this->Makefile->IssueMessage(cmake::AUTHOR_WARNING,
 823            this->Makefile->GetPolicies()->
 824              GetPolicyWarning(cmPolicies::CMP0009));
 825          }
 826        break;
 827      case cmPolicies::REQUIRED_IF_USED:
 828      case cmPolicies::REQUIRED_ALWAYS:
 829        this->SetError("policy CMP0009 error");
 830        this->Makefile->IssueMessage(cmake::FATAL_ERROR,
 831          this->Makefile->GetPolicies()->
 832            GetRequiredPolicyError(cmPolicies::CMP0009));
 833        return false;
 834      }
 835    }
 836
 837  this->Makefile->AddDefinition(variable.c_str(), output.c_str());
 838  return true;
 839}
 840
 841//----------------------------------------------------------------------------
 842bool cmFileCommand::HandleMakeDirectoryCommand(
 843  std::vector<std::string> const& args)
 844{
 845  if(args.size() < 2 )
 846    {
 847    this->SetError("called with incorrect number of arguments");
 848    return false;
 849    }
 850
 851  std::vector<std::string>::const_iterator i = args.begin();
 852
 853  i++; // Get rid of subcommand
 854
 855  std::string expr;
 856  for ( ; i != args.end(); ++i )
 857    {
 858    const std::string* cdir = &(*i);
 859    if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
 860      {
 861      expr = this->Makefile->GetCurrentDirectory();
 862      expr += "/" + *i;
 863      cdir = &expr;
 864      }
 865    if ( !this->Makefile->CanIWriteThisFile(cdir->c_str()) )
 866      {
 867      std::string e = "attempted to create a directory: " + *cdir
 868        + " into a source directory.";
 869      this->SetError(e.c_str());
 870      cmSystemTools::SetFatalErrorOccured();
 871      return false;
 872      }
 873    if ( !cmSystemTools::MakeDirectory(cdir->c_str()) )
 874      {
 875      std::string error = "problem creating directory: " + *cdir;
 876      this->SetError(error.c_str());
 877      return false;
 878      }
 879    }
 880  return true;
 881}
 882
 883//----------------------------------------------------------------------------
 884bool
 885cmFileCommand::HandleDifferentCommand(std::vector<std::string> const& args)
 886{
 887  /*
 888    FILE(DIFFERENT <variable> FILES <lhs> <rhs>)
 889   */
 890
 891  // Evaluate arguments.
 892  const char* file_lhs = 0;
 893  const char* file_rhs = 0;
 894  const char* var = 0;
 895  enum Doing { DoingNone, DoingVar, DoingFileLHS, DoingFileRHS };
 896  Doing doing = DoingVar;
 897  for(unsigned int i=1; i < args.size(); ++i)
 898    {
 899    if(args[i] == "FILES")
 900      {
 901      doing = DoingFileLHS;
 902      }
 903    else if(doing == DoingVar)
 904      {
 905      var = args[i].c_str();
 906      doing = DoingNone;
 907      }
 908    else if(doing == DoingFileLHS)
 909      {
 910      file_lhs = args[i].c_str();
 911      doing = DoingFileRHS;
 912      }
 913    else if(doing == DoingFileRHS)
 914      {
 915      file_rhs = args[i].c_str();
 916      doing = DoingNone;
 917      }
 918    else
 919      {
 920      cmOStringStream e;
 921      e << "DIFFERENT given unknown argument " << args[i];
 922      this->SetError(e.str().c_str());
 923      return false;
 924      }
 925    }
 926  if(!var)
 927    {
 928    this->SetError("DIFFERENT not given result variable name.");
 929    return false;
 930    }
 931  if(!file_lhs || !file_rhs)
 932    {
 933    this->SetError("DIFFERENT not given FILES option with two file names.");
 934    return false;
 935    }
 936
 937  // Compare the files.
 938  const char* result =
 939    cmSystemTools::FilesDiffer(file_lhs, file_rhs)? "1" : "0";
 940  this->Makefile->AddDefinition(var, result);
 941  return true;
 942}
 943
 944//----------------------------------------------------------------------------
 945// File installation helper class.
 946struct cmFileCopier
 947{
 948  cmFileCopier(cmFileCommand* command, const char* name = "COPY"):
 949    FileCommand(command),
 950    Makefile(command->GetMakefile()),
 951    Name(name),
 952    Always(false),
 953    MatchlessFiles(true),
 954    FilePermissions(0),
 955    DirPermissions(0),
 956    CurrentMatchRule(0),
 957    UseGivenPermissionsFile(false),
 958    UseGivenPermissionsDir(false),
 959    UseSourcePermissions(true),
 960    Doing(DoingNone)
 961    {
 962    }
 963  virtual ~cmFileCopier() {}
 964
 965  bool Run(std::vector<std::string> const& args);
 966protected:
 967
 968  cmFileCommand* FileCommand;
 969  cmMakefile* Makefile;
 970  const char* Name;
 971  bool Always;
 972  cmFileTimeComparison FileTimes;
 973
 974  // Whether to install a file not matching any expression.
 975  bool MatchlessFiles;
 976
 977  // Permissions for files and directories installed by this object.
 978  mode_t FilePermissions;
 979  mode_t DirPermissions;
 980
 981  // Properties set by pattern and regex match rules.
 982  struct MatchProperties
 983  {
 984    bool Exclude;
 985    mode_t Permissions;
 986    MatchProperties(): Exclude(false), Permissions(0) {}
 987  };
 988  struct MatchRule;
 989  friend struct MatchRule;
 990  struct MatchRule
 991  {
 992    cmsys::RegularExpression Regex;
 993    MatchProperties Properties;
 994    std::string RegexString;
 995    MatchRule(std::string const& regex):
 996      Regex(regex.c_str()), RegexString(regex) {}
 997  };
 998  std::vector<MatchRule> MatchRules;
 999
1000  // Get the properties from rules matching this input file.
1001  MatchProperties CollectMatchProperties(const char* file)
1002    {
1003    // Match rules are case-insensitive on some platforms.
1004#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
1005    std::string lower = cmSystemTools::LowerCase(file);
1006    const char* file_to_match = lower.c_str();
1007#else
1008    const char* file_to_match = file;
1009#endif
1010
1011    // Collect properties from all matching rules.
1012    bool matched = false;
1013    MatchProperties result;
1014    for(std::vector<MatchRule>::iterator mr = this->MatchRules.begin();
1015        mr != this->MatchRules.end(); ++mr)
1016      {
1017      if(mr->Regex.find(file_to_match))
1018        {
1019        matched = true;
1020        result.Exclude |= mr->Properties.Exclude;
1021        result.Permissions |= mr->Properties.Permissions;
1022        }
1023      }
1024    if(!matched && !this->MatchlessFiles)
1025      {
1026      result.Exclude = !cmSystemTools::FileIsDirectory(file);
1027      }
1028    return result;
1029    }
1030
1031  bool SetPermissions(const char* toFile, mode_t permissions)
1032    {
1033    if(permissions && !cmSystemTools::SetPermissions(toFile, permissions))
1034      {
1035      cmOStringStream e;
1036      e << this->Name << " cannot set permissions on \"" << toFile << "\"";
1037      this->FileCommand->SetError(e.str().c_str());
1038      return false;
1039      }
1040    return true;
1041    }
1042
1043  // Translate an argument to a permissions bit.
1044  bool CheckPermissions(std::string const& arg, mode_t& permissions)
1045    {
1046    if(arg == "OWNER_READ")         { permissions |= mode_owner_read; }
1047    else if(arg == "OWNER_WRITE")   { permissions |= mode_owner_write; }
1048    else if(arg == "OWNER_EXECUTE") { permissions |= mode_owner_execute; }
1049    else if(arg == "GROUP_READ")    { permissions |= mode_group_read; }
1050    else if(arg == "GROUP_WRITE")   { permissions |= mode_group_write; }
1051    else if(arg == "GROUP_EXECUTE") { permissions |= mode_group_execute; }
1052    else if(arg == "WORLD_READ")    { permissions |= mode_world_read; }
1053    else if(arg == "WORLD_WRITE")   { permissions |= mode_world_write; }
1054    else if(arg == "WORLD_EXECUTE") { permissions |= mode_world_execute; }
1055    else if(arg == "SETUID")        { permissions |= mode_setuid; }
1056    else if(arg == "SETGID")        { permissions |= mode_setgid; }
1057    else
1058      {
1059      cmOStringStream e;
1060      e << this->Name << " given invalid permission \"" << arg << "\".";
1061      this->FileCommand->SetError(e.str().c_str());
1062      return false;
1063      }
1064    return true;
1065    }
1066
1067  bool InstallSymlink(const char* fromFile, const char* toFile);
1068  bool InstallFile(const char* fromFile, const char* toFile,
1069                   MatchProperties const& match_properties);
1070  bool InstallDirectory(const char* source, const char* destination,
1071                        MatchProperties const& match_properties);
1072  virtual bool Install(const char* fromFile, const char* toFile);
1073  virtual std::string const& ToName(std::string const& fromName)
1074    { return fromName; }
1075
1076  enum Type
1077  {
1078    TypeFile,
1079    TypeDir,
1080    TypeLink
1081  };
1082  virtual void ReportCopy(const char*, Type, bool) {}
1083  virtual bool ReportMissing(const char* fromFile)
1084    {
1085    // The input file does not exist and installation is not optional.
1086    cmOStringStream e;
1087    e << this->Name << " cannot find \"" << fromFile << "\".";
1088    this->FileCommand->SetError(e.str().c_str());
1089    return false;
1090    }
1091
1092  MatchRule* CurrentMatchRule;
1093  bool UseGivenPermissionsFile;
1094  bool UseGivenPermissionsDir;
1095  bool UseSourcePermissions;
1096  std::string Destination;
1097  std::vector<std::string> Files;
1098  int Doing;
1099
1100  virtual bool Parse(std::vector<std::string> const& args);
1101  enum
1102  {
1103    DoingNone,
1104    DoingError,
1105    DoingDestination,
1106    DoingFiles,
1107    DoingPattern,
1108    DoingRegex,
1109    DoingPermissionsFile,
1110    DoingPermissionsDir,
1111    DoingPermissionsMatch,
1112    DoingLast1
1113  };
1114  virtual bool CheckKeyword(std::string const& arg);
1115  virtual bool CheckValue(std::string const& arg);
1116
1117  void NotBeforeMatch(std::string const& arg)
1118    {
1119    cmOStringStream e;
1120    e << "option " << arg << " may not appear before PATTERN or REGEX.";
1121    this->FileCommand->SetError(e.str().c_str());
1122    this->Doing = DoingError;
1123    }
1124  void NotAfterMatch(std::string const& arg)
1125    {
1126    cmOStringStream e;
1127    e << "option " << arg << " may not appear after PATTERN or REGEX.";
1128    this->FileCommand->SetError(e.str().c_str());
1129    this->Doing = DoingError;
1130    }
1131  virtual void DefaultFilePermissions()
1132    {
1133    // Use read/write permissions.
1134    this->FilePermissions = 0;
1135    this->FilePermissions |= mode_owner_read;
1136    this->FilePermissions |= mode_owner_write;
1137    this->FilePermissions |= mode_group_read;
1138    this->FilePermissions |= mode_world_read;
1139    }
1140  virtual void DefaultDirectoryPermissions()
1141    {
1142    // Use read/write/executable permissions.
1143    this->DirPermissions = 0;
1144    this->DirPermissions |= mode_owner_read;
1145    this->DirPermissions |= mode_owner_write;
1146    this->DirPermissions |= mode_owner_execute;
1147    this->DirPermissions |= mode_group_read;
1148    this->DirPermissions |= mode_group_execute;
1149    this->DirPermissions |= mode_world_read;
1150    this->DirPermissions |= mode_world_execute;
1151    }
1152};
1153
1154//----------------------------------------------------------------------------
1155bool cmFileCopier::Parse(std::vector<std::string> const& args)
1156{
1157  this->Doing = DoingFiles;
1158  for(unsigned int i=1; i < args.size(); ++i)
1159    {
1160    // Check this argument.
1161    if(!this->CheckKeyword(args[i]) &&
1162       !this->CheckValue(args[i]))
1163      {
1164      cmOStringStream e;
1165      e << "called with unknown argument \"" << args[i] << "\".";
1166      this->FileCommand->SetError(e.str().c_str());
1167      return false;
1168      }
1169
1170    // Quit if an argument is invalid.
1171    if(this->Doing == DoingError)
1172      {
1173      return false;
1174      }
1175    }
1176
1177  // Require a destination.
1178  if(this->Destination.empty())
1179    {
1180    cmOStringStream e;
1181    e << this->Name << " given no DESTINATION";
1182    this->FileCommand->SetError(e.str().c_str());
1183    return false;
1184    }
1185
1186  // If file permissions were not specified set default permissions.
1187  if(!this->UseGivenPermissionsFile && !this->UseSourcePermissions)
1188    {
1189    this->DefaultFilePermissions();
1190    }
1191
1192  // If directory permissions were not specified set default permissions.
1193  if(!this->UseGivenPermissionsDir && !this->UseSourcePermissions)
1194    {
1195    this->DefaultDirectoryPermissions();
1196    }
1197
1198  return true;
1199}
1200
1201//----------------------------------------------------------------------------
1202bool cmFileCopier::CheckKeyword(std::string const& arg)
1203{
1204  if(arg == "DESTINATION")
1205    {
1206    if(this->CurrentMatchRule)
1207      {
1208      this->NotAfterMatch(arg);
1209      }
1210    else
1211      {
1212      this->Doing = DoingDestination;
1213      }
1214    }
1215  else if(arg == "PATTERN")
1216    {
1217    this->Doing = DoingPattern;
1218    }
1219  else if(arg == "REGEX")
1220    {
1221    this->Doing = DoingRegex;
1222    }
1223  else if(arg == "EXCLUDE")
1224    {
1225    // Add this property to the current match rule.
1226    if(this->CurrentMatchRule)
1227      {
1228      this->CurrentMatchRule->Properties.Exclude = true;
1229      this->Doing = DoingNone;
1230      }
1231    else
1232      {
1233      this->NotBeforeMatch(arg);
1234      }
1235    }
1236  else if(arg == "PERMISSIONS")
1237    {
1238    if(this->CurrentMatchRule)
1239      {
1240      this->Doing = DoingPermissionsMatch;
1241      }
1242    else
1243      {
1244      this->NotBeforeMatch(arg);
1245      }
1246    }
1247  else if(arg == "FILE_PERMISSIONS")
1248    {
1249    if(this->CurrentMatchRule)
1250      {
1251      this->NotAfterMatch(arg);
1252      }
1253    else
1254      {
1255      this->Doing = DoingPermissionsFile;
1256      this->UseGivenPermissionsFile = true;
1257      }
1258    }
1259  else if(arg == "DIRECTORY_PERMISSIONS")
1260    {
1261    if(this->CurrentMatchRule)
1262      {
1263      this->NotAfterMatch(arg);
1264      }
1265    else
1266      {
1267      this->Doing = DoingPermissionsDir;
1268      this->UseGivenPermissionsDir = true;
1269      }
1270    }
1271  else if(arg == "USE_SOURCE_PERMISSIONS")
1272    {
1273    if(this->CurrentMatchRule)
1274      {
1275      this->NotAfterMatch(arg);
1276      }
1277    else
1278      {
1279      this->Doing = DoingNone;
1280      this->UseSourcePermissions = true;
1281      }
1282    }
1283  else if(arg == "NO_SOURCE_PERMISSIONS")
1284    {
1285    if(this->CurrentMatchRule)
1286      {
1287      this->NotAfterMatch(arg);
1288      }
1289    else
1290      {
1291      this->Doing = DoingNone;
1292      this->UseSourcePermissions = false;
1293      }
1294    }
1295  else if(arg == "FILES_MATCHING")
1296    {
1297    if(this->CurrentMatchRule)
1298      {
1299      this->NotAfterMatch(arg);
1300      }
1301    else
1302      {
1303      this->Doing = DoingNone;
1304      this->MatchlessFiles = false;
1305      }
1306    }
1307  else
1308    {
1309    return false;
1310    }
1311  return true;
1312}
1313
1314//----------------------------------------------------------------------------
1315bool cmFileCopier::CheckValue(std::string const& arg)
1316{
1317  switch(this->Doing)
1318    {
1319    case DoingFiles:
1320      if(arg.empty() || cmSystemTools::FileIsFullPath(arg.c_str()))
1321        {
1322        this->Files.push_back(arg);
1323        }
1324      else
1325        {
1326        std::string file = this->Makefile->GetCurrentDirectory();
1327        file += "/" + arg;
1328        this->Files.push_back(file);
1329        }
1330      break;
1331    case DoingDestination:
1332      if(arg.empty() || cmSystemTools::FileIsFullPath(arg.c_str()))
1333        {
1334        this->Destination = arg;
1335        }
1336      else
1337        {
1338        this->Destination = this->Makefile->GetCurrentOutputDirectory();
1339        this->Destination += "/" + arg;
1340        }
1341      this->Doing = DoingNone;
1342      break;
1343    case DoingPattern:
1344      {
1345      // Convert the pattern to a regular expression.  Require a
1346      // leading slash and trailing end-of-string in the matched
1347      // string to make sure the pattern matches only whole file
1348      // names.
1349      std::string regex = "/";
1350      regex += cmsys::Glob::PatternToRegex(arg, false);
1351      regex += "$";
1352      this->MatchRules.push_back(MatchRule(regex));
1353      this->CurrentMatchRule = &*(this->MatchRules.end()-1);
1354      if(this->CurrentMatchRule->Regex.is_valid())
1355        {
1356        this->Doing = DoingNone;
1357        }
1358      else
1359        {
1360        cmOStringStream e;
1361        e << "could not compile PATTERN \"" << arg << "\".";
1362        this->FileCommand->SetError(e.str().c_str());
1363        this->Doing = DoingError;
1364        }
1365      }
1366      break;
1367    case DoingRegex:
1368      this->MatchRules.push_back(MatchRule(arg));
1369      this->CurrentMatchRule = &*(this->MatchRules.end()-1);
1370      if(this->CurrentMatchRule->Regex.is_valid())
1371        {
1372        this->Doing = DoingNone;
1373        }
1374      else
1375        {
1376        cmOStringStream e;
1377        e << "could not compile REGEX \"" << arg << "\".";
1378        this->FileCommand->SetError(e.str().c_str());
1379        this->Doing = DoingError;
1380        }
1381      break;
1382    case DoingPermissionsFile:
1383      if(!this->CheckPermissions(arg, this->FilePermissions))
1384        {
1385        this->Doing = DoingError;
1386        }
1387      break;
1388    case DoingPermissionsDir:
1389      if(!this->CheckPermissions(arg, this->DirPermissions))
1390        {
1391        this->Doing = DoingError;
1392        }
1393      break;
1394    case DoingPermissionsMatch:
1395      if(!this->CheckPermissions(
1396           arg, this->CurrentMatchRule->Properties.Permissions))
1397        {
1398        this->Doing = DoingError;
1399        }
1400      break;
1401    default:
1402      return false;
1403    }
1404  return true;
1405}
1406
1407//----------------------------------------------------------------------------
1408bool cmFileCopier::Run(std::vector<std::string> const& args)
1409{
1410  if(!this->Parse(args))
1411    {
1412    return false;
1413    }
1414
1415  std::vector<std::string> const& files = this->Files;
1416  for(std::vector<std::string>::size_type i = 0; i < files.size(); ++i)
1417    {
1418    // Split the input file into its directory and name components.
1419    std::vector<std::string> fromPathComponents;
1420    cmSystemTools::SplitPath(files[i].c_str(), fromPathComponents);
1421    std::string fromName = *(fromPathComponents.end()-1);
1422    std::string fromDir = cmSystemTools::JoinPath(fromPathComponents.begin(),
1423                                                  fromPathComponents.end()-1);
1424
1425    // Compute the full path to the destination file.
1426    std::string toFile = this->Destination;
1427    std::string const& toName = this->ToName(fromName);
1428    if(!toName.empty())
1429      {
1430      toFile += "/";
1431      toFile += toName;
1432      }
1433
1434    // Construct the full path to the source file.  The file name may
1435    // have been changed above.
1436    std::string fromFile = fromDir;
1437    if(!fromName.empty())
1438      {
1439      fromFile += "/";
1440      fromFile += fromName;
1441      }
1442
1443    if(!this->Install(fromFile.c_str(), toFile.c_str()))
1444      {
1445      return false;
1446      }
1447    }
1448  return true;
1449}
1450
1451//----------------------------------------------------------------------------
1452bool cmFileCopier::Install(const char* fromFile, const char* toFile)
1453{
1454  if(!*fromFile)
1455    {
1456    cmOStringStream e;
1457    e << "INSTALL encountered an empty string input file name.";
1458    this->FileCommand->SetError(e.str().c_str());
1459    return false;
1460    }
1461
1462  // Collect any properties matching this file name.
1463  MatchProperties match_properties = this->CollectMatchProperties(fromFile);
1464
1465  // Skip the file if it is excluded.
1466  if(match_properties.Exclude)
1467    {
1468    return true;
1469    }
1470
1471  if(cmSystemTools::SameFile(fromFile, toFile))
1472    {
1473    return true;
1474    }
1475  else if(cmSystemTools::FileIsSymlink(fromFile))
1476    {
1477    return this->InstallSymlink(fromFile, toFile);
1478    }
1479  else if(cmSystemTools::FileIsDirectory(fromFile))
1480    {
1481    return this->InstallDirectory(fromFile, toFile, match_properties);
1482    }
1483  else if(cmSystemTools::FileExists(fromFile))
1484    {
1485    return this->InstallFile(fromFile, toFile, match_properties);
1486    }
1487  return this->ReportMissing(fromFile);
1488}
1489
1490//----------------------------------------------------------------------------
1491bool cmFileCopier::InstallSymlink(const char* fromFile, const char* toFile)
1492{
1493  // Read the original symlink.
1494  std::string symlinkTarget;
1495  if(!cmSystemTools::ReadSymlink(fromFile, symlinkTarget))
1496    {
1497    cmOStringStream e;
1498    e << this->Name << " cannot read symlink \"" << fromFile
1499      << "\" to duplicate at \"" << toFile << "\".";
1500    this->FileCommand->SetError(e.str().c_str());
1501    return false;
1502    }
1503
1504  // Compare the symlink value to that at the destination if not
1505  // always installing.
1506  bool copy = true;
1507  if(!this->Always)
1508    {
1509    std::string oldSymlinkTarget;
1510    if(cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget))
1511      {
1512      if(symlinkTarget == oldSymlinkTarget)
1513        {
1514        copy = false;
1515        }
1516      }
1517    }
1518
1519  // Inform the user about this file installation.
1520  this->ReportCopy(toFile, TypeLink, copy);
1521
1522  if(copy)
1523    {
1524    // Remove the destination file so we can always create the symlink.
1525    cmSystemTools::RemoveFile(toFile);
1526
1527    // Create the symlink.
1528    if(!cmSystemTools::CreateSymlink(symlinkTarget.c_str(), toFile))
1529      {
1530      cmOStringStream e;
1531      e << this->Name <<  " cannot duplicate symlink \"" << fromFile
1532        << "\" at \"" << toFile << "\".";
1533      this->FileCommand->SetError(e.str().c_str());
1534      return false;
1535      }
1536    }
1537
1538  return true;
1539}
1540
1541//----------------------------------------------------------------------------
1542bool cmFileCopier::InstallFile(const char* fromFile, const char* toFile,
1543                               MatchProperties const& match_properties)
1544{
1545  // Determine whether we will copy the file.
1546  bool copy = true;
1547  if(!this->Always)
1548    {
1549    // If both files exist with the same time do not copy.
1550    if(!this->FileTimes.FileTimesDiffer(fromFile, toFile))
1551      {
1552      copy = false;
1553      }
1554    }
1555
1556  // Inform the user about this file installation.
1557  this->ReportCopy(toFile, TypeFile, copy);
1558
1559  // Copy the file.
1560  if(copy && !cmSystemTools::CopyAFile(fromFile, toFile, true))
1561    {
1562    cmOStringStream e;
1563    e << this->Name << " cannot copy file \"" << fromFile
1564      << "\" to \"" << toFile << "\".";
1565    this->FileCommand->SetError(e.str().c_str());
1566    return false;
1567    }
1568
1569  // Set the file modification time of the destination file.
1570  if(copy && !this->Always)
1571    {
1572    // Add write permission so we can set the file time.
1573    // Permissions are set unconditionally below anyway.
1574    mode_t perm = 0;
1575    if(cmSystemTools::GetPermissions(toFile, perm))
1576      {
1577      cmSystemTools::SetPermissions(toFile, perm | mode_owner_write);
1578      }
1579    if (!cmSystemTools::CopyFileTime(fromFile, toFile))
1580      {
1581      cmOStringStream e;
1582      e << this->Name << " cannot set modification time on \""
1583        << toFile << "\"";
1584      this->FileCommand->SetError(e.str().c_str());
1585      return false;
1586      }
1587    }
1588
1589  // Set permissions of the destination file.
1590  mode_t permissions = (match_properties.Permissions?
1591                        match_properties.Permissions : this->FilePermissions);
1592  if(!permissions)
1593    {
1594    // No permissions were explicitly provided but the user requested
1595    // that the source file permissions be used.
1596    cmSystemTools::GetPermissions(fromFile, permissions);
1597    }
1598  return this->SetPermissions(toFile, permissions);
1599}
1600
1601//----------------------------------------------------------------------------
1602bool cmFileCopier::InstallDirectory(const char* source,
1603                                    const char* destination,
1604                                    MatchProperties const& match_properties)
1605{
1606  // Inform the user about this directory installation.
1607  this->ReportCopy(destination, TypeDir, true);
1608
1609  // Make sure the destination directory exists.
1610  if(!cmSystemTools::MakeDirectory(destination))
1611    {
1612    cmOStringStream e;
1613    e << this->Name << " cannot make directory \"" << destination << "\": "
1614      << cmSystemTools::GetLastSystemError();
1615    this->FileCommand->SetError(e.str().c_str());
1616    return false;
1617    }
1618
1619  // Compute the requested permissions for the destination directory.
1620  mode_t permissions = (match_properties.Permissions?
1621                        match_properties.Permissions : this->DirPermissions);
1622  if(!permissions)
1623    {
1624    // No permissions were explicitly provided but the user requested
1625    // that the source directory permissions be used.
1626    cmSystemTools::GetPermissions(source, permissions);
1627    }
1628
1629  // Compute the set of permissions required on this directory to
1630  // recursively install files and subdirectories safely.
1631  mode_t required_permissions =
1632    mode_owner_read | mode_owner_write | mode_owner_execute;
1633
1634  // If the required permissions are specified it is safe to set the
1635  // final permissions now.  Otherwise we must add the required
1636  // permissions temporarily during file installation.
1637  mode_t permissions_before = 0;
1638  mode_t permissions_after = 0;
1639  if((permissions & required_permissions) == required_permissions)
1640    {
1641    permissions_before = permissions;
1642    }
1643  else
1644    {
1645    permissions_before = permissions | required_permissions;
1646    permissions_after = permissions;
1647    }
1648
1649  // Set the required permissions of the destination directory.
1650  if(!this->SetPermissions(destination, permissions_before))
1651    {
1652    return false;
1653    }
1654
1655  // Load the directory contents to traverse it recursively.
1656  cmsys::Directory dir;
1657  if(source && *source)
1658    {
1659    dir.Load(source);
1660    }
1661  unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
1662  for(unsigned long fileNum = 0; fileNum < numFiles; ++fileNum)
1663    {
1664    if(!(strcmp(dir.GetFile(fileNum), ".") == 0 ||
1665         strcmp(dir.GetFile(fileNum), "..") == 0))
1666      {
1667      cmsys_stl::string fromPath = source;
1668      fromPath += "/";
1669      fromPath += dir.GetFile(fileNum);
1670      std::string toPath = destination;
1671      toPath += "/";
1672      toPath += dir.GetFile(fileNum);
1673      if(!this->Install(fromPath.c_str(), toPath.c_str()))
1674        {
1675        return false;
1676        }
1677      }
1678    }
1679
1680  // Set the requested permissions of the destination directory.
1681  return this->SetPermissions(destination, permissions_after);
1682}
1683
1684//----------------------------------------------------------------------------
1685bool cmFileCommand::HandleCopyCommand(std::vector<std::string> const& args)
1686{
1687  cmFileCopier copier(this);
1688  return copier.Run(args);
1689}
1690
1691//----------------------------------------------------------------------------
1692struct cmFileInstaller: public cmFileCopier
1693{
1694  cmFileInstaller(cmFileCommand* command):
1695    cmFileCopier(command, "INSTALL"),
1696    InstallType(cmInstallType_FILES),
1697    Optional(false),
1698    DestDirLength(0)
1699    {
1700    // Installation does not use source permissions by default.
1701    this->UseSourcePermissions = false;
1702    // Check whether to copy files always or only if they have changed.
1703    this->Always =
1704      cmSystemTools::IsOn(cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS"));
1705    // Get the current manifest.
1706    this->Manifest =
1707      this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
1708    }
1709  ~cmFileInstaller()
1710    {
1711    // Save the updated install manifest.
1712    this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
1713                                  this->Manifest.c_str());
1714    }
1715
1716protected:
1717  cmInstallType InstallType;
1718  bool Optional;
1719  int DestDirLength;
1720  std::string Rename;
1721
1722  std::string Manifest;
1723  void ManifestAppend(std::string const& file)
1724    {
1725    this->Manifest += ";";
1726    this->Manifest += file.substr(this->DestDirLength);
1727    }
1728
1729  virtual std::string const& ToName(std::string const& fromName)
1730    { return this->Rename.empty()? fromName : this->Rename; }
1731
1732  virtual void ReportCopy(const char* toFile, Type type, bool copy)
1733    {
1734    std::string message = (copy? "Installing: " : "Up-to-date: ");
1735    message += toFile;
1736    this->Makefile->DisplayStatus(message.c_str(), -1);
1737    if(type != TypeDir)
1738      {
1739      // Add the file to the manifest.
1740      this->ManifestAppend(toFile);
1741      }
1742    }
1743  virtual bool ReportMissing(const char* fromFile)
1744    {
1745    return (this->Optional ||
1746            this->cmFileCopier::ReportMissing(fromFile));
1747    }
1748  virtual bool Install(const char* fromFile, const char* toFile)
1749    {
1750    // Support installing from empty source to make a directory.
1751    if(this->InstallType == cmInstallType_DIRECTORY && !*fromFile)
1752      {
1753      return this->InstallDirectory(fromFile, toFile, MatchProperties());
1754      }
1755    return this->cmFileCopier::Install(fromFile, toFile);
1756    }
1757
1758  virtual bool Parse(std::vector<std::string> const& args);
1759  enum
1760  {
1761    DoingType = DoingLast1,
1762    DoingRename,
1763    DoingLast2
1764  };
1765  virtual bool CheckKeyword(std::string const& arg);
1766  virtual bool CheckValue(std::string const& arg);
1767  virtual void DefaultFilePermissions()
1768    {
1769    this->cmFileCopier::DefaultFilePermissions();
1770    // Add execute permissions based on the target type.
1771    switch(this->InstallType)
1772      {
1773      case cmInstallType_SHARED_LIBRARY:
1774      case cmInstallType_MODULE_LIBRARY:
1775        if(this->Makefile->IsOn("CMAKE_INSTALL_SO_NO_EXE"))
1776          {
1777          break;
1778          }
1779      case cmInstallType_EXECUTABLE:
1780      case cmInstallType_PROGRAMS:
1781        this->FilePermissions |= mode_owner_execute;
1782        this->FilePermissions |= mode_group_execute;
1783        this->FilePermissions |= mode_world_execute;
1784        break;
1785      default: break;
1786      }
1787    }
1788  bool GetTargetTypeFr

Large files files are truncated, but you can click here to view the full file