Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / cmFileCommand.cxx
blobc681174cabb501ed9d2bb782547f3fabaf9468a5
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmFileCommand.cxx,v $
5 Language: C++
6 Date: $Date: 2009-03-06 14:14:57 $
7 Version: $Revision: 1.118 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmFileCommand.h"
18 #include "cmake.h"
19 #include "cmHexFileConverter.h"
20 #include "cmFileTimeComparison.h"
22 #if defined(CMAKE_BUILD_WITH_CMAKE)
23 #include "cm_curl.h"
24 #endif
26 #undef GetCurrentDirectory
27 #include <sys/types.h>
28 #include <sys/stat.h>
30 #include <cmsys/Directory.hxx>
31 #include <cmsys/Glob.hxx>
32 #include <cmsys/RegularExpression.hxx>
34 // Table of permissions flags.
35 #if defined(_WIN32) && !defined(__CYGWIN__)
36 static mode_t mode_owner_read = S_IREAD;
37 static mode_t mode_owner_write = S_IWRITE;
38 static mode_t mode_owner_execute = S_IEXEC;
39 static mode_t mode_group_read = 0;
40 static mode_t mode_group_write = 0;
41 static mode_t mode_group_execute = 0;
42 static mode_t mode_world_read = 0;
43 static mode_t mode_world_write = 0;
44 static mode_t mode_world_execute = 0;
45 static mode_t mode_setuid = 0;
46 static mode_t mode_setgid = 0;
47 #else
48 static mode_t mode_owner_read = S_IRUSR;
49 static mode_t mode_owner_write = S_IWUSR;
50 static mode_t mode_owner_execute = S_IXUSR;
51 static mode_t mode_group_read = S_IRGRP;
52 static mode_t mode_group_write = S_IWGRP;
53 static mode_t mode_group_execute = S_IXGRP;
54 static mode_t mode_world_read = S_IROTH;
55 static mode_t mode_world_write = S_IWOTH;
56 static mode_t mode_world_execute = S_IXOTH;
57 static mode_t mode_setuid = S_ISUID;
58 static mode_t mode_setgid = S_ISGID;
59 #endif
61 // cmLibraryCommand
62 bool cmFileCommand
63 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
65 if(args.size() < 2 )
67 this->SetError("must be called with at least two arguments.");
68 return false;
70 std::string subCommand = args[0];
71 if ( subCommand == "WRITE" )
73 return this->HandleWriteCommand(args, false);
75 else if ( subCommand == "APPEND" )
77 return this->HandleWriteCommand(args, true);
79 else if ( subCommand == "DOWNLOAD" )
81 return this->HandleDownloadCommand(args);
83 else if ( subCommand == "READ" )
85 return this->HandleReadCommand(args);
87 else if ( subCommand == "STRINGS" )
89 return this->HandleStringsCommand(args);
91 else if ( subCommand == "GLOB" )
93 return this->HandleGlobCommand(args, false);
95 else if ( subCommand == "GLOB_RECURSE" )
97 return this->HandleGlobCommand(args, true);
99 else if ( subCommand == "MAKE_DIRECTORY" )
101 return this->HandleMakeDirectoryCommand(args);
103 else if ( subCommand == "REMOVE" )
105 return this->HandleRemove(args, false);
107 else if ( subCommand == "REMOVE_RECURSE" )
109 return this->HandleRemove(args, true);
111 else if ( subCommand == "INSTALL" )
113 return this->HandleInstallCommand(args);
115 else if ( subCommand == "DIFFERENT" )
117 return this->HandleDifferentCommand(args);
119 else if ( subCommand == "RPATH_CHANGE" || subCommand == "CHRPATH" )
121 return this->HandleRPathChangeCommand(args);
123 else if ( subCommand == "RPATH_CHECK" )
125 return this->HandleRPathCheckCommand(args);
127 else if ( subCommand == "RPATH_REMOVE" )
129 return this->HandleRPathRemoveCommand(args);
131 else if ( subCommand == "RELATIVE_PATH" )
133 return this->HandleRelativePathCommand(args);
135 else if ( subCommand == "TO_CMAKE_PATH" )
137 return this->HandleCMakePathCommand(args, false);
139 else if ( subCommand == "TO_NATIVE_PATH" )
141 return this->HandleCMakePathCommand(args, true);
144 std::string e = "does not recognize sub-command "+subCommand;
145 this->SetError(e.c_str());
146 return false;
149 //----------------------------------------------------------------------------
150 bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args,
151 bool append)
153 std::string message;
154 std::vector<std::string>::const_iterator i = args.begin();
156 i++; // Get rid of subcommand
158 std::string fileName = *i;
159 if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
161 fileName = this->Makefile->GetCurrentDirectory();
162 fileName += "/" + *i;
165 i++;
167 for(;i != args.end(); ++i)
169 message += *i;
171 if ( !this->Makefile->CanIWriteThisFile(fileName.c_str()) )
173 std::string e
174 = "attempted to write a file: " + fileName +
175 " into a source directory.";
176 this->SetError(e.c_str());
177 cmSystemTools::SetFatalErrorOccured();
178 return false;
180 std::string dir = cmSystemTools::GetFilenamePath(fileName);
181 cmSystemTools::MakeDirectory(dir.c_str());
183 mode_t mode =
184 #if defined( _MSC_VER ) || defined( __MINGW32__ )
185 S_IREAD | S_IWRITE
186 #elif defined( __BORLANDC__ )
187 S_IRUSR | S_IWUSR
188 #else
189 S_IRUSR | S_IWUSR |
190 S_IRGRP |
191 S_IROTH
192 #endif
195 // Set permissions to writable
196 if ( cmSystemTools::GetPermissions(fileName.c_str(), mode) )
198 cmSystemTools::SetPermissions(fileName.c_str(),
199 #if defined( _MSC_VER ) || defined( __MINGW32__ )
200 S_IREAD | S_IWRITE
201 #else
202 S_IRUSR | S_IWUSR
203 #endif
206 // If GetPermissions fails, pretend like it is ok. File open will fail if
207 // the file is not writable
208 std::ofstream file(fileName.c_str(), append?std::ios::app: std::ios::out);
209 if ( !file )
211 std::string error = "Internal CMake error when trying to open file: ";
212 error += fileName.c_str();
213 error += " for writing.";
214 this->SetError(error.c_str());
215 return false;
217 file << message;
218 file.close();
219 cmSystemTools::SetPermissions(fileName.c_str(), mode);
220 return true;
223 //----------------------------------------------------------------------------
224 bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args)
226 if ( args.size() < 3 )
228 this->SetError("READ must be called with at least two additional "
229 "arguments");
230 return false;
233 cmCommandArgumentsHelper argHelper;
234 cmCommandArgumentGroup group;
236 cmCAString readArg (&argHelper, "READ");
237 cmCAString fileNameArg (&argHelper, 0);
238 cmCAString resultArg (&argHelper, 0);
240 cmCAString offsetArg (&argHelper, "OFFSET", &group);
241 cmCAString limitArg (&argHelper, "LIMIT", &group);
242 cmCAEnabler hexOutputArg (&argHelper, "HEX", &group);
243 readArg.Follows(0);
244 fileNameArg.Follows(&readArg);
245 resultArg.Follows(&fileNameArg);
246 group.Follows(&resultArg);
247 argHelper.Parse(&args, 0);
249 std::string fileName = fileNameArg.GetString();
250 if ( !cmsys::SystemTools::FileIsFullPath(fileName.c_str()) )
252 fileName = this->Makefile->GetCurrentDirectory();
253 fileName += "/" + fileNameArg.GetString();
256 std::string variable = resultArg.GetString();
258 // Open the specified file.
259 #if defined(_WIN32) || defined(__CYGWIN__)
260 std::ifstream file(fileName.c_str(), std::ios::in |
261 (hexOutputArg.IsEnabled() ? std::ios::binary : std::ios::in));
262 #else
263 std::ifstream file(fileName.c_str(), std::ios::in);
264 #endif
266 if ( !file )
268 std::string error = "Internal CMake error when trying to open file: ";
269 error += fileName.c_str();
270 error += " for reading.";
271 this->SetError(error.c_str());
272 return false;
275 // is there a limit?
276 long sizeLimit = -1;
277 if (limitArg.GetString().size() > 0)
279 sizeLimit = atoi(limitArg.GetCString());
282 // is there an offset?
283 long offset = 0;
284 if (offsetArg.GetString().size() > 0)
286 offset = atoi(offsetArg.GetCString());
289 file.seekg(offset);
291 std::string output;
293 if (hexOutputArg.IsEnabled())
295 // Convert part of the file into hex code
296 int c;
297 while((sizeLimit != 0) && (c = file.get(), file))
299 char hex[4];
300 sprintf(hex, "%x", c&0xff);
301 output += hex;
302 if (sizeLimit > 0)
304 sizeLimit--;
308 else
310 std::string line;
311 bool has_newline = false;
312 while (sizeLimit != 0 &&
313 cmSystemTools::GetLineFromStream(file, line, &has_newline,
314 sizeLimit) )
316 if (sizeLimit > 0)
318 sizeLimit = sizeLimit - static_cast<long>(line.size());
319 if (has_newline)
321 sizeLimit--;
323 if (sizeLimit < 0)
325 sizeLimit = 0;
328 output += line;
329 if ( has_newline )
331 output += "\n";
335 this->Makefile->AddDefinition(variable.c_str(), output.c_str());
336 return true;
339 //----------------------------------------------------------------------------
340 bool cmFileCommand::HandleStringsCommand(std::vector<std::string> const& args)
342 if(args.size() < 3)
344 this->SetError("STRINGS requires a file name and output variable");
345 return false;
348 // Get the file to read.
349 std::string fileName = args[1];
350 if(!cmsys::SystemTools::FileIsFullPath(fileName.c_str()))
352 fileName = this->Makefile->GetCurrentDirectory();
353 fileName += "/" + args[1];
356 // Get the variable in which to store the results.
357 std::string outVar = args[2];
359 // Parse the options.
360 enum { arg_none,
361 arg_limit_input,
362 arg_limit_output,
363 arg_limit_count,
364 arg_length_minimum,
365 arg_length_maximum,
366 arg__maximum,
367 arg_regex };
368 unsigned int minlen = 0;
369 unsigned int maxlen = 0;
370 int limit_input = -1;
371 int limit_output = -1;
372 unsigned int limit_count = 0;
373 cmsys::RegularExpression regex;
374 bool have_regex = false;
375 bool newline_consume = false;
376 bool hex_conversion_enabled = true;
377 int arg_mode = arg_none;
378 for(unsigned int i=3; i < args.size(); ++i)
380 if(args[i] == "LIMIT_INPUT")
382 arg_mode = arg_limit_input;
384 else if(args[i] == "LIMIT_OUTPUT")
386 arg_mode = arg_limit_output;
388 else if(args[i] == "LIMIT_COUNT")
390 arg_mode = arg_limit_count;
392 else if(args[i] == "LENGTH_MINIMUM")
394 arg_mode = arg_length_minimum;
396 else if(args[i] == "LENGTH_MAXIMUM")
398 arg_mode = arg_length_maximum;
400 else if(args[i] == "REGEX")
402 arg_mode = arg_regex;
404 else if(args[i] == "NEWLINE_CONSUME")
406 newline_consume = true;
407 arg_mode = arg_none;
409 else if(args[i] == "NO_HEX_CONVERSION")
411 hex_conversion_enabled = false;
412 arg_mode = arg_none;
414 else if(arg_mode == arg_limit_input)
416 if(sscanf(args[i].c_str(), "%d", &limit_input) != 1 ||
417 limit_input < 0)
419 cmOStringStream e;
420 e << "STRINGS option LIMIT_INPUT value \""
421 << args[i] << "\" is not an unsigned integer.";
422 this->SetError(e.str().c_str());
423 return false;
425 arg_mode = arg_none;
427 else if(arg_mode == arg_limit_output)
429 if(sscanf(args[i].c_str(), "%d", &limit_output) != 1 ||
430 limit_output < 0)
432 cmOStringStream e;
433 e << "STRINGS option LIMIT_OUTPUT value \""
434 << args[i] << "\" is not an unsigned integer.";
435 this->SetError(e.str().c_str());
436 return false;
438 arg_mode = arg_none;
440 else if(arg_mode == arg_limit_count)
442 int count;
443 if(sscanf(args[i].c_str(), "%d", &count) != 1 || count < 0)
445 cmOStringStream e;
446 e << "STRINGS option LIMIT_COUNT value \""
447 << args[i] << "\" is not an unsigned integer.";
448 this->SetError(e.str().c_str());
449 return false;
451 limit_count = count;
452 arg_mode = arg_none;
454 else if(arg_mode == arg_length_minimum)
456 int len;
457 if(sscanf(args[i].c_str(), "%d", &len) != 1 || len < 0)
459 cmOStringStream e;
460 e << "STRINGS option LENGTH_MINIMUM value \""
461 << args[i] << "\" is not an unsigned integer.";
462 this->SetError(e.str().c_str());
463 return false;
465 minlen = len;
466 arg_mode = arg_none;
468 else if(arg_mode == arg_length_maximum)
470 int len;
471 if(sscanf(args[i].c_str(), "%d", &len) != 1 || len < 0)
473 cmOStringStream e;
474 e << "STRINGS option LENGTH_MAXIMUM value \""
475 << args[i] << "\" is not an unsigned integer.";
476 this->SetError(e.str().c_str());
477 return false;
479 maxlen = len;
480 arg_mode = arg_none;
482 else if(arg_mode == arg_regex)
484 if(!regex.compile(args[i].c_str()))
486 cmOStringStream e;
487 e << "STRINGS option REGEX value \""
488 << args[i] << "\" could not be compiled.";
489 this->SetError(e.str().c_str());
490 return false;
492 have_regex = true;
493 arg_mode = arg_none;
495 else
497 cmOStringStream e;
498 e << "STRINGS given unknown argument \""
499 << args[i] << "\"";
500 this->SetError(e.str().c_str());
501 return false;
505 if (hex_conversion_enabled)
507 // TODO: should work without temp file, but just on a memory buffer
508 std::string binaryFileName = this->Makefile->GetCurrentOutputDirectory();
509 binaryFileName += cmake::GetCMakeFilesDirectory();
510 binaryFileName += "/FileCommandStringsBinaryFile";
511 if(cmHexFileConverter::TryConvert(fileName.c_str(),binaryFileName.c_str()))
513 fileName = binaryFileName;
517 // Open the specified file.
518 #if defined(_WIN32) || defined(__CYGWIN__)
519 std::ifstream fin(fileName.c_str(), std::ios::in | std::ios::binary);
520 #else
521 std::ifstream fin(fileName.c_str(), std::ios::in);
522 #endif
523 if(!fin)
525 cmOStringStream e;
526 e << "STRINGS file \"" << fileName << "\" cannot be read.";
527 this->SetError(e.str().c_str());
528 return false;
531 // Parse strings out of the file.
532 int output_size = 0;
533 std::vector<std::string> strings;
534 std::string s;
535 int c;
536 while((!limit_count || strings.size() < limit_count) &&
537 (limit_input < 0 || static_cast<int>(fin.tellg()) < limit_input) &&
538 (c = fin.get(), fin))
540 if(c == '\0')
542 // A terminating null character has been found. Check if the
543 // current string matches the requirements. Since it was
544 // terminated by a null character, we require that the length be
545 // at least one no matter what the user specified.
546 if(s.length() >= minlen && s.length() >= 1 &&
547 (!have_regex || regex.find(s.c_str())))
549 output_size += static_cast<int>(s.size()) + 1;
550 if(limit_output >= 0 && output_size >= limit_output)
552 s = "";
553 break;
555 strings.push_back(s);
558 // Reset the string to empty.
559 s = "";
561 else if(c == '\n' && !newline_consume)
563 // The current line has been terminated. Check if the current
564 // string matches the requirements. The length may now be as
565 // low as zero since blank lines are allowed.
566 if(s.length() >= minlen &&
567 (!have_regex || regex.find(s.c_str())))
569 output_size += static_cast<int>(s.size()) + 1;
570 if(limit_output >= 0 && output_size >= limit_output)
572 s = "";
573 break;
575 strings.push_back(s);
578 // Reset the string to empty.
579 s = "";
581 else if(c == '\r')
583 // Ignore CR character to make output always have UNIX newlines.
585 else if(c >= 0x20 && c < 0x7F || c == '\t' || c == '\f' ||
586 (c == '\n' && newline_consume))
588 // This is an ASCII character that may be part of a string.
589 s += c;
591 else
593 // This is a non-string character. Reset the string to emtpy.
594 s = "";
597 // Terminate a string if the maximum length is reached.
598 if(maxlen > 0 && s.size() == maxlen)
600 if(s.length() >= minlen &&
601 (!have_regex || regex.find(s.c_str())))
603 output_size += static_cast<int>(s.size()) + 1;
604 if(limit_output >= 0 && output_size >= limit_output)
606 s = "";
607 break;
609 strings.push_back(s);
611 s = "";
615 // If there is a non-empty current string we have hit the end of the
616 // input file or the input size limit. Check if the current string
617 // matches the requirements.
618 if((!limit_count || strings.size() < limit_count) &&
619 !s.empty() && s.length() >= minlen &&
620 (!have_regex || regex.find(s.c_str())))
622 output_size += static_cast<int>(s.size()) + 1;
623 if(limit_output < 0 || output_size < limit_output)
625 strings.push_back(s);
629 // Encode the result in a CMake list.
630 const char* sep = "";
631 std::string output;
632 for(std::vector<std::string>::const_iterator si = strings.begin();
633 si != strings.end(); ++si)
635 // Separate the strings in the output to make it a list.
636 output += sep;
637 sep = ";";
639 // Store the string in the output, but escape semicolons to
640 // make sure it is a list.
641 std::string const& sr = *si;
642 for(unsigned int i=0; i < sr.size(); ++i)
644 if(sr[i] == ';')
646 output += '\\';
648 output += sr[i];
652 // Save the output in a makefile variable.
653 this->Makefile->AddDefinition(outVar.c_str(), output.c_str());
654 return true;
657 //----------------------------------------------------------------------------
658 bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
659 bool recurse)
661 if ( args.size() < 2 )
663 this->SetError("GLOB requires at least a variable name");
664 return false;
667 std::vector<std::string>::const_iterator i = args.begin();
669 i++; // Get rid of subcommand
671 std::string variable = *i;
672 i++;
673 cmsys::Glob g;
674 g.SetRecurse(recurse);
676 bool explicitFollowSymlinks = false;
677 cmPolicies::PolicyStatus status =
678 this->Makefile->GetPolicyStatus(cmPolicies::CMP0009);
679 if(recurse)
681 switch(status)
683 case cmPolicies::NEW:
684 g.RecurseThroughSymlinksOff();
685 break;
686 case cmPolicies::OLD:
687 case cmPolicies::WARN:
688 case cmPolicies::REQUIRED_IF_USED:
689 case cmPolicies::REQUIRED_ALWAYS:
690 g.RecurseThroughSymlinksOn();
691 break;
695 std::string output = "";
696 bool first = true;
697 for ( ; i != args.end(); ++i )
699 if ( recurse && (*i == "FOLLOW_SYMLINKS") )
701 explicitFollowSymlinks = true;
702 g.RecurseThroughSymlinksOn();
703 ++i;
704 if ( i == args.end() )
706 this->SetError(
707 "GLOB_RECURSE requires a glob expression after FOLLOW_SYMLINKS");
708 return false;
712 if ( *i == "RELATIVE" )
714 ++i; // skip RELATIVE
715 if ( i == args.end() )
717 this->SetError("GLOB requires a directory after the RELATIVE tag");
718 return false;
720 g.SetRelative(i->c_str());
721 ++i;
722 if(i == args.end())
724 this->SetError("GLOB requires a glob expression after the directory");
725 return false;
729 if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
731 std::string expr = this->Makefile->GetCurrentDirectory();
732 // Handle script mode
733 if ( expr.size() > 0 )
735 expr += "/" + *i;
736 g.FindFiles(expr);
738 else
740 g.FindFiles(*i);
743 else
745 g.FindFiles(*i);
748 std::vector<std::string>::size_type cc;
749 std::vector<std::string>& files = g.GetFiles();
750 for ( cc = 0; cc < files.size(); cc ++ )
752 if ( !first )
754 output += ";";
756 output += files[cc];
757 first = false;
761 if(recurse && !explicitFollowSymlinks)
763 switch (status)
765 case cmPolicies::NEW:
766 // Correct behavior, yay!
767 break;
768 case cmPolicies::OLD:
769 // Probably not really the expected behavior, but the author explicitly
770 // asked for the old behavior... no warning.
771 case cmPolicies::WARN:
772 // Possibly unexpected old behavior *and* we actually traversed
773 // symlinks without being explicitly asked to: warn the author.
774 if(g.GetFollowedSymlinkCount() != 0)
776 this->Makefile->IssueMessage(cmake::AUTHOR_WARNING,
777 this->Makefile->GetPolicies()->
778 GetPolicyWarning(cmPolicies::CMP0009));
780 break;
781 case cmPolicies::REQUIRED_IF_USED:
782 case cmPolicies::REQUIRED_ALWAYS:
783 this->SetError("policy CMP0009 error");
784 this->Makefile->IssueMessage(cmake::FATAL_ERROR,
785 this->Makefile->GetPolicies()->
786 GetRequiredPolicyError(cmPolicies::CMP0009));
787 return false;
791 this->Makefile->AddDefinition(variable.c_str(), output.c_str());
792 return true;
795 //----------------------------------------------------------------------------
796 bool cmFileCommand::HandleMakeDirectoryCommand(
797 std::vector<std::string> const& args)
799 if(args.size() < 2 )
801 this->SetError("called with incorrect number of arguments");
802 return false;
805 std::vector<std::string>::const_iterator i = args.begin();
807 i++; // Get rid of subcommand
809 std::string expr;
810 for ( ; i != args.end(); ++i )
812 const std::string* cdir = &(*i);
813 if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
815 expr = this->Makefile->GetCurrentDirectory();
816 expr += "/" + *i;
817 cdir = &expr;
819 if ( !this->Makefile->CanIWriteThisFile(cdir->c_str()) )
821 std::string e = "attempted to create a directory: " + *cdir
822 + " into a source directory.";
823 this->SetError(e.c_str());
824 cmSystemTools::SetFatalErrorOccured();
825 return false;
827 if ( !cmSystemTools::MakeDirectory(cdir->c_str()) )
829 std::string error = "problem creating directory: " + *cdir;
830 this->SetError(error.c_str());
831 return false;
834 return true;
837 //----------------------------------------------------------------------------
838 bool
839 cmFileCommand::HandleDifferentCommand(std::vector<std::string> const& args)
842 FILE(DIFFERENT <variable> FILES <lhs> <rhs>)
845 // Evaluate arguments.
846 const char* file_lhs = 0;
847 const char* file_rhs = 0;
848 const char* var = 0;
849 enum Doing { DoingNone, DoingVar, DoingFileLHS, DoingFileRHS };
850 Doing doing = DoingVar;
851 for(unsigned int i=1; i < args.size(); ++i)
853 if(args[i] == "FILES")
855 doing = DoingFileLHS;
857 else if(doing == DoingVar)
859 var = args[i].c_str();
860 doing = DoingNone;
862 else if(doing == DoingFileLHS)
864 file_lhs = args[i].c_str();
865 doing = DoingFileRHS;
867 else if(doing == DoingFileRHS)
869 file_rhs = args[i].c_str();
870 doing = DoingNone;
872 else
874 cmOStringStream e;
875 e << "DIFFERENT given unknown argument " << args[i];
876 this->SetError(e.str().c_str());
877 return false;
880 if(!var)
882 this->SetError("DIFFERENT not given result variable name.");
883 return false;
885 if(!file_lhs || !file_rhs)
887 this->SetError("DIFFERENT not given FILES option with two file names.");
888 return false;
891 // Compare the files.
892 const char* result =
893 cmSystemTools::FilesDiffer(file_lhs, file_rhs)? "1" : "0";
894 this->Makefile->AddDefinition(var, result);
895 return true;
898 //----------------------------------------------------------------------------
899 // File installation helper class.
900 struct cmFileInstaller
902 // Methods to actually install files.
903 bool InstallFile(const char* fromFile, const char* toFile, bool always);
904 bool InstallDirectory(const char* source, const char* destination,
905 bool always);
907 // All instances need the file command and makefile using them.
908 cmFileInstaller(cmFileCommand* fc, cmMakefile* mf):
909 FileCommand(fc), Makefile(mf), DestDirLength(0), MatchlessFiles(true)
911 // Get the current manifest.
912 this->Manifest =
913 this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
915 ~cmFileInstaller()
917 // Save the updated install manifest.
918 this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
919 this->Manifest.c_str());
922 private:
923 cmFileCommand* FileCommand;
924 cmMakefile* Makefile;
925 cmFileTimeComparison FileTimes;
926 public:
928 // The length of the destdir setting.
929 int DestDirLength;
931 // Whether to install a file not matching any expression.
932 bool MatchlessFiles;
934 // The current file manifest (semicolon separated list).
935 std::string Manifest;
937 // Permissions for files and directories installed by this object.
938 mode_t FilePermissions;
939 mode_t DirPermissions;
941 // Properties set by pattern and regex match rules.
942 struct MatchProperties
944 bool Exclude;
945 mode_t Permissions;
946 MatchProperties(): Exclude(false), Permissions(0) {}
948 struct MatchRule
950 cmsys::RegularExpression Regex;
951 MatchProperties Properties;
952 std::string RegexString;
953 MatchRule(std::string const& regex):
954 Regex(regex.c_str()), RegexString(regex) {}
956 std::vector<MatchRule> MatchRules;
958 // Get the properties from rules matching this input file.
959 MatchProperties CollectMatchProperties(const char* file,
960 bool isDirectory)
962 // Match rules are case-insensitive on some platforms.
963 #if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
964 std::string lower = cmSystemTools::LowerCase(file);
965 file = lower.c_str();
966 #endif
968 // Collect properties from all matching rules.
969 bool matched = false;
970 MatchProperties result;
971 for(std::vector<MatchRule>::iterator mr = this->MatchRules.begin();
972 mr != this->MatchRules.end(); ++mr)
974 if(mr->Regex.find(file))
976 matched = true;
977 result.Exclude |= mr->Properties.Exclude;
978 result.Permissions |= mr->Properties.Permissions;
981 if(!matched && !this->MatchlessFiles && !isDirectory)
983 result.Exclude = true;
985 return result;
988 // Append a file to the installation manifest.
989 void ManifestAppend(std::string const& file)
991 this->Manifest += ";";
992 this->Manifest += file.substr(this->DestDirLength);
995 // Translate an argument to a permissions bit.
996 bool CheckPermissions(std::string const& arg, mode_t& permissions)
998 if(arg == "OWNER_READ") { permissions |= mode_owner_read; }
999 else if(arg == "OWNER_WRITE") { permissions |= mode_owner_write; }
1000 else if(arg == "OWNER_EXECUTE") { permissions |= mode_owner_execute; }
1001 else if(arg == "GROUP_READ") { permissions |= mode_group_read; }
1002 else if(arg == "GROUP_WRITE") { permissions |= mode_group_write; }
1003 else if(arg == "GROUP_EXECUTE") { permissions |= mode_group_execute; }
1004 else if(arg == "WORLD_READ") { permissions |= mode_world_read; }
1005 else if(arg == "WORLD_WRITE") { permissions |= mode_world_write; }
1006 else if(arg == "WORLD_EXECUTE") { permissions |= mode_world_execute; }
1007 else if(arg == "SETUID") { permissions |= mode_setuid; }
1008 else if(arg == "SETGID") { permissions |= mode_setgid; }
1009 else
1011 cmOStringStream e;
1012 e << "INSTALL given invalid permission \"" << arg << "\".";
1013 this->FileCommand->SetError(e.str().c_str());
1014 return false;
1016 return true;
1019 private:
1020 bool InstallSymlink(const char* fromFile, const char* toFile, bool always);
1023 //----------------------------------------------------------------------------
1024 bool cmFileInstaller::InstallSymlink(const char* fromFile, const char* toFile,
1025 bool always)
1027 // Read the original symlink.
1028 std::string symlinkTarget;
1029 if(!cmSystemTools::ReadSymlink(fromFile, symlinkTarget))
1031 cmOStringStream e;
1032 e << "INSTALL cannot read symlink \"" << fromFile
1033 << "\" to duplicate at \"" << toFile << "\".";
1034 this->FileCommand->SetError(e.str().c_str());
1035 return false;
1038 // Compare the symlink value to that at the destination if not
1039 // always installing.
1040 bool copy = true;
1041 if(!always)
1043 std::string oldSymlinkTarget;
1044 if(cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget))
1046 if(symlinkTarget == oldSymlinkTarget)
1048 copy = false;
1053 // Inform the user about this file installation.
1054 std::string message = (copy? "Installing: " : "Up-to-date: ");
1055 message += toFile;
1056 this->Makefile->DisplayStatus(message.c_str(), -1);
1058 if(copy)
1060 // Remove the destination file so we can always create the symlink.
1061 cmSystemTools::RemoveFile(toFile);
1063 // Create the symlink.
1064 if(!cmSystemTools::CreateSymlink(symlinkTarget.c_str(), toFile))
1066 cmOStringStream e;
1067 e << "INSTALL cannot duplicate symlink \"" << fromFile
1068 << "\" at \"" << toFile << "\".";
1069 this->FileCommand->SetError(e.str().c_str());
1070 return false;
1074 // Add the file to the manifest.
1075 this->ManifestAppend(toFile);
1077 return true;
1080 //----------------------------------------------------------------------------
1081 bool cmFileInstaller::InstallFile(const char* fromFile, const char* toFile,
1082 bool always)
1084 // Collect any properties matching this file name.
1085 MatchProperties match_properties =
1086 this->CollectMatchProperties(fromFile, false);
1088 // Skip the file if it is excluded.
1089 if(match_properties.Exclude)
1091 return true;
1094 // Short-circuit for symbolic links.
1095 if(cmSystemTools::FileIsSymlink(fromFile))
1097 return this->InstallSymlink(fromFile, toFile, always);
1100 // Determine whether we will copy the file.
1101 bool copy = true;
1102 if(!always)
1104 // If both files exist with the same time do not copy.
1105 if(!this->FileTimes.FileTimesDiffer(fromFile, toFile))
1107 copy = false;
1111 // Inform the user about this file installation.
1112 std::string message = (copy? "Installing: " : "Up-to-date: ");
1113 message += toFile;
1114 this->Makefile->DisplayStatus(message.c_str(), -1);
1116 // Copy the file.
1117 if(copy && !cmSystemTools::CopyAFile(fromFile, toFile, true, false))
1119 cmOStringStream e;
1120 e << "INSTALL cannot copy file \"" << fromFile
1121 << "\" to \"" << toFile << "\".";
1122 this->FileCommand->SetError(e.str().c_str());
1123 return false;
1126 // Add the file to the manifest.
1127 this->ManifestAppend(toFile);
1129 // Set the file modification time of the destination file.
1130 if(copy && !always)
1132 if (!cmSystemTools::CopyFileTime(fromFile, toFile))
1134 cmOStringStream e;
1135 e << "Problem setting modification time on file \"" << toFile << "\"";
1136 this->FileCommand->SetError(e.str().c_str());
1137 return false;
1141 // Set permissions of the destination file.
1142 mode_t permissions = (match_properties.Permissions?
1143 match_properties.Permissions : this->FilePermissions);
1144 if(!permissions)
1146 // No permissions were explicitly provided but the user requested
1147 // that the source file permissions be used.
1148 cmSystemTools::GetPermissions(fromFile, permissions);
1150 if(permissions && !cmSystemTools::SetPermissions(toFile, permissions))
1152 cmOStringStream e;
1153 e << "Problem setting permissions on file \"" << toFile << "\"";
1154 this->FileCommand->SetError(e.str().c_str());
1155 return false;
1158 return true;
1161 //----------------------------------------------------------------------------
1162 bool cmFileInstaller::InstallDirectory(const char* source,
1163 const char* destination,
1164 bool always)
1166 // Collect any properties matching this directory name.
1167 MatchProperties match_properties =
1168 this->CollectMatchProperties(source, true);
1170 // Skip the directory if it is excluded.
1171 if(match_properties.Exclude)
1173 return true;
1176 // Short-circuit for symbolic links.
1177 if(cmSystemTools::FileIsSymlink(source))
1179 return this->InstallSymlink(source, destination, always);
1182 // Inform the user about this directory installation.
1183 std::string message = "Installing: ";
1184 message += destination;
1185 this->Makefile->DisplayStatus(message.c_str(), -1);
1187 // Make sure the destination directory exists.
1188 if(!cmSystemTools::MakeDirectory(destination))
1190 return false;
1193 // Compute the requested permissions for the destination directory.
1194 mode_t permissions = (match_properties.Permissions?
1195 match_properties.Permissions : this->DirPermissions);
1196 if(!permissions)
1198 // No permissions were explicitly provided but the user requested
1199 // that the source directory permissions be used.
1200 cmSystemTools::GetPermissions(source, permissions);
1203 // Compute the set of permissions required on this directory to
1204 // recursively install files and subdirectories safely.
1205 mode_t required_permissions =
1206 mode_owner_read | mode_owner_write | mode_owner_execute;
1208 // If the required permissions are specified it is safe to set the
1209 // final permissions now. Otherwise we must add the required
1210 // permissions temporarily during file installation.
1211 mode_t permissions_before = 0;
1212 mode_t permissions_after = 0;
1213 if(permissions & required_permissions)
1215 permissions_before = permissions;
1217 else
1219 permissions_before = permissions | required_permissions;
1220 permissions_after = permissions;
1223 // Set the required permissions of the destination directory.
1224 if(permissions_before &&
1225 !cmSystemTools::SetPermissions(destination, permissions_before))
1227 cmOStringStream e;
1228 e << "Problem setting permissions on directory \""
1229 << destination << "\"";
1230 this->FileCommand->SetError(e.str().c_str());
1231 return false;
1234 // Load the directory contents to traverse it recursively.
1235 cmsys::Directory dir;
1236 if(source && *source)
1238 dir.Load(source);
1240 unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
1241 for(unsigned long fileNum = 0; fileNum < numFiles; ++fileNum)
1243 if(!(strcmp(dir.GetFile(fileNum), ".") == 0 ||
1244 strcmp(dir.GetFile(fileNum), "..") == 0))
1246 cmsys_stl::string fromPath = source;
1247 fromPath += "/";
1248 fromPath += dir.GetFile(fileNum);
1249 if(cmSystemTools::FileIsDirectory(fromPath.c_str()))
1251 cmsys_stl::string toDir = destination;
1252 toDir += "/";
1253 toDir += dir.GetFile(fileNum);
1254 if(!this->InstallDirectory(fromPath.c_str(), toDir.c_str(), always))
1256 return false;
1259 else
1261 // Install this file.
1262 std::string toFile = destination;
1263 toFile += "/";
1264 toFile += dir.GetFile(fileNum);
1265 if(!this->InstallFile(fromPath.c_str(), toFile.c_str(), always))
1267 return false;
1273 // Set the requested permissions of the destination directory.
1274 if(permissions_after &&
1275 !cmSystemTools::SetPermissions(destination, permissions_after))
1277 cmOStringStream e;
1278 e << "Problem setting permissions on directory \"" << destination << "\"";
1279 this->FileCommand->SetError(e.str().c_str());
1280 return false;
1283 return true;
1286 //----------------------------------------------------------------------------
1287 void cmFileCommand::HandleInstallPermissions(cmFileInstaller& installer,
1288 mode_t& permissions_file,
1289 mode_t& permissions_dir,
1290 int itype,
1291 bool use_given_permissions_file,
1292 bool use_given_permissions_dir,
1293 bool use_source_permissions) const
1295 // Choose a default for shared library permissions.
1296 bool install_so_no_exe = this->Makefile->IsOn("CMAKE_INSTALL_SO_NO_EXE");
1297 // If file permissions were not specified set default permissions
1298 // for this target type.
1299 if(!use_given_permissions_file && !use_source_permissions)
1301 switch(itype)
1303 case cmTarget::SHARED_LIBRARY:
1304 case cmTarget::MODULE_LIBRARY:
1305 if(install_so_no_exe)
1307 // Use read/write permissions.
1308 permissions_file = 0;
1309 permissions_file |= mode_owner_read;
1310 permissions_file |= mode_owner_write;
1311 permissions_file |= mode_group_read;
1312 permissions_file |= mode_world_read;
1313 break;
1315 case cmTarget::EXECUTABLE:
1316 case cmTarget::INSTALL_PROGRAMS:
1317 // Use read/write/executable permissions.
1318 permissions_file = 0;
1319 permissions_file |= mode_owner_read;
1320 permissions_file |= mode_owner_write;
1321 permissions_file |= mode_owner_execute;
1322 permissions_file |= mode_group_read;
1323 permissions_file |= mode_group_execute;
1324 permissions_file |= mode_world_read;
1325 permissions_file |= mode_world_execute;
1326 break;
1327 default:
1328 // Use read/write permissions.
1329 permissions_file = 0;
1330 permissions_file |= mode_owner_read;
1331 permissions_file |= mode_owner_write;
1332 permissions_file |= mode_group_read;
1333 permissions_file |= mode_world_read;
1334 break;
1338 // If directory permissions were not specified set default permissions.
1339 if(!use_given_permissions_dir && !use_source_permissions)
1341 // Use read/write/executable permissions.
1342 permissions_dir = 0;
1343 permissions_dir |= mode_owner_read;
1344 permissions_dir |= mode_owner_write;
1345 permissions_dir |= mode_owner_execute;
1346 permissions_dir |= mode_group_read;
1347 permissions_dir |= mode_group_execute;
1348 permissions_dir |= mode_world_read;
1349 permissions_dir |= mode_world_execute;
1351 // Set the installer permissions.
1352 installer.FilePermissions = permissions_file;
1353 installer.DirPermissions = permissions_dir;
1356 //----------------------------------------------------------------------------
1357 void cmFileCommand
1358 ::GetTargetTypeFromString(const std::string& stype, int& itype) const
1360 if ( stype == "EXECUTABLE" )
1362 itype = cmTarget::EXECUTABLE;
1364 else if ( stype == "PROGRAM" )
1366 itype = cmTarget::INSTALL_PROGRAMS;
1368 else if ( stype == "STATIC_LIBRARY" )
1370 itype = cmTarget::STATIC_LIBRARY;
1372 else if ( stype == "SHARED_LIBRARY" )
1374 itype = cmTarget::SHARED_LIBRARY;
1376 else if ( stype == "MODULE" )
1378 itype = cmTarget::MODULE_LIBRARY;
1380 else if ( stype == "DIRECTORY" )
1382 itype = cmTarget::INSTALL_DIRECTORY;
1387 //----------------------------------------------------------------------------
1388 bool cmFileCommand::HandleInstallDestination(cmFileInstaller& installer,
1389 std::string& destination)
1391 // allow for / to be a valid destination
1392 if ( destination.size() < 2 && destination != "/" )
1394 this->SetError("called with inapropriate arguments. "
1395 "No DESTINATION provided or .");
1396 return false;
1399 const char* destdir = cmSystemTools::GetEnv("DESTDIR");
1400 if ( destdir && *destdir )
1402 std::string sdestdir = destdir;
1403 cmSystemTools::ConvertToUnixSlashes(sdestdir);
1404 char ch1 = destination[0];
1405 char ch2 = destination[1];
1406 char ch3 = 0;
1407 if ( destination.size() > 2 )
1409 ch3 = destination[2];
1411 int skip = 0;
1412 if ( ch1 != '/' )
1414 int relative = 0;
1415 if ( ( ch1 >= 'a' && ch1 <= 'z' || ch1 >= 'A' && ch1 <= 'Z' ) &&
1416 ch2 == ':' )
1418 // Assume windows
1419 // let's do some destdir magic:
1420 skip = 2;
1421 if ( ch3 != '/' )
1423 relative = 1;
1426 else
1428 relative = 1;
1430 if ( relative )
1432 // This is relative path on unix or windows. Since we are doing
1433 // destdir, this case does not make sense.
1434 this->SetError("called with relative DESTINATION. This "
1435 "does not make sense when using DESTDIR. Specify "
1436 "absolute path or remove DESTDIR environment variable.");
1437 return false;
1440 else
1442 if ( ch2 == '/' )
1444 // looks like a network path.
1445 std::string message = "called with network path DESTINATION. This "
1446 "does not make sense when using DESTDIR. Specify local "
1447 "absolute path or remove DESTDIR environment variable."
1448 "\nDESTINATION=\n";
1449 message += destination;
1450 this->SetError(message.c_str());
1451 return false;
1454 destination = sdestdir + (destination.c_str() + skip);
1455 installer.DestDirLength = int(sdestdir.size());
1458 if ( !cmSystemTools::FileExists(destination.c_str()) )
1460 if ( !cmSystemTools::MakeDirectory(destination.c_str()) )
1462 std::string errstring = "cannot create directory: " + destination +
1463 ". Maybe need administrative privileges.";
1464 this->SetError(errstring.c_str());
1465 return false;
1468 if ( !cmSystemTools::FileIsDirectory(destination.c_str()) )
1470 std::string errstring = "INSTALL destination: " + destination +
1471 " is not a directory.";
1472 this->SetError(errstring.c_str());
1473 return false;
1475 return true;
1478 //----------------------------------------------------------------------------
1479 bool
1480 cmFileCommand::HandleRPathChangeCommand(std::vector<std::string> const& args)
1482 // Evaluate arguments.
1483 const char* file = 0;
1484 const char* oldRPath = 0;
1485 const char* newRPath = 0;
1486 enum Doing { DoingNone, DoingFile, DoingOld, DoingNew };
1487 Doing doing = DoingNone;
1488 for(unsigned int i=1; i < args.size(); ++i)
1490 if(args[i] == "OLD_RPATH")
1492 doing = DoingOld;
1494 else if(args[i] == "NEW_RPATH")
1496 doing = DoingNew;
1498 else if(args[i] == "FILE")
1500 doing = DoingFile;
1502 else if(doing == DoingFile)
1504 file = args[i].c_str();
1505 doing = DoingNone;
1507 else if(doing == DoingOld)
1509 oldRPath = args[i].c_str();
1510 doing = DoingNone;
1512 else if(doing == DoingNew)
1514 newRPath = args[i].c_str();
1515 doing = DoingNone;
1517 else
1519 cmOStringStream e;
1520 e << "RPATH_CHANGE given unknown argument " << args[i];
1521 this->SetError(e.str().c_str());
1522 return false;
1525 if(!file)
1527 this->SetError("RPATH_CHANGE not given FILE option.");
1528 return false;
1530 if(!oldRPath)
1532 this->SetError("RPATH_CHANGE not given OLD_RPATH option.");
1533 return false;
1535 if(!newRPath)
1537 this->SetError("RPATH_CHANGE not given NEW_RPATH option.");
1538 return false;
1540 if(!cmSystemTools::FileExists(file, true))
1542 cmOStringStream e;
1543 e << "RPATH_CHANGE given FILE \"" << file << "\" that does not exist.";
1544 this->SetError(e.str().c_str());
1545 return false;
1547 bool success = true;
1548 cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
1549 bool have_ft = cmSystemTools::FileTimeGet(file, ft);
1550 std::string emsg;
1551 bool changed;
1552 if(!cmSystemTools::ChangeRPath(file, oldRPath, newRPath, &emsg, &changed))
1554 cmOStringStream e;
1555 e << "RPATH_CHANGE could not write new RPATH:\n"
1556 << " " << newRPath << "\n"
1557 << "to the file:\n"
1558 << " " << file << "\n"
1559 << emsg;
1560 this->SetError(e.str().c_str());
1561 success = false;
1563 if(success)
1565 if(changed)
1567 std::string message = "Set runtime path of \"";
1568 message += file;
1569 message += "\" to \"";
1570 message += newRPath;
1571 message += "\"";
1572 this->Makefile->DisplayStatus(message.c_str(), -1);
1574 if(have_ft)
1576 cmSystemTools::FileTimeSet(file, ft);
1579 cmSystemTools::FileTimeDelete(ft);
1580 return success;
1583 //----------------------------------------------------------------------------
1584 bool
1585 cmFileCommand::HandleRPathRemoveCommand(std::vector<std::string> const& args)
1587 // Evaluate arguments.
1588 const char* file = 0;
1589 enum Doing { DoingNone, DoingFile };
1590 Doing doing = DoingNone;
1591 for(unsigned int i=1; i < args.size(); ++i)
1593 if(args[i] == "FILE")
1595 doing = DoingFile;
1597 else if(doing == DoingFile)
1599 file = args[i].c_str();
1600 doing = DoingNone;
1602 else
1604 cmOStringStream e;
1605 e << "RPATH_REMOVE given unknown argument " << args[i];
1606 this->SetError(e.str().c_str());
1607 return false;
1610 if(!file)
1612 this->SetError("RPATH_REMOVE not given FILE option.");
1613 return false;
1615 if(!cmSystemTools::FileExists(file, true))
1617 cmOStringStream e;
1618 e << "RPATH_REMOVE given FILE \"" << file << "\" that does not exist.";
1619 this->SetError(e.str().c_str());
1620 return false;
1622 bool success = true;
1623 cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
1624 bool have_ft = cmSystemTools::FileTimeGet(file, ft);
1625 std::string emsg;
1626 bool removed;
1627 if(!cmSystemTools::RemoveRPath(file, &emsg, &removed))
1629 cmOStringStream e;
1630 e << "RPATH_REMOVE could not remove RPATH from file:\n"
1631 << " " << file << "\n"
1632 << emsg;
1633 this->SetError(e.str().c_str());
1634 success = false;
1636 if(success)
1638 if(removed)
1640 std::string message = "Removed runtime path from \"";
1641 message += file;
1642 message += "\"";
1643 this->Makefile->DisplayStatus(message.c_str(), -1);
1645 if(have_ft)
1647 cmSystemTools::FileTimeSet(file, ft);
1650 cmSystemTools::FileTimeDelete(ft);
1651 return success;
1654 //----------------------------------------------------------------------------
1655 bool
1656 cmFileCommand::HandleRPathCheckCommand(std::vector<std::string> const& args)
1658 // Evaluate arguments.
1659 const char* file = 0;
1660 const char* rpath = 0;
1661 enum Doing { DoingNone, DoingFile, DoingRPath };
1662 Doing doing = DoingNone;
1663 for(unsigned int i=1; i < args.size(); ++i)
1665 if(args[i] == "RPATH")
1667 doing = DoingRPath;
1669 else if(args[i] == "FILE")
1671 doing = DoingFile;
1673 else if(doing == DoingFile)
1675 file = args[i].c_str();
1676 doing = DoingNone;
1678 else if(doing == DoingRPath)
1680 rpath = args[i].c_str();
1681 doing = DoingNone;
1683 else
1685 cmOStringStream e;
1686 e << "RPATH_CHECK given unknown argument " << args[i];
1687 this->SetError(e.str().c_str());
1688 return false;
1691 if(!file)
1693 this->SetError("RPATH_CHECK not given FILE option.");
1694 return false;
1696 if(!rpath)
1698 this->SetError("RPATH_CHECK not given RPATH option.");
1699 return false;
1702 // If the file exists but does not have the desired RPath then
1703 // delete it. This is used during installation to re-install a file
1704 // if its RPath will change.
1705 if(cmSystemTools::FileExists(file, true) &&
1706 !cmSystemTools::CheckRPath(file, rpath))
1708 cmSystemTools::RemoveFile(file);
1711 return true;
1714 //----------------------------------------------------------------------------
1715 bool cmFileCommand::HandleInstallCommand(std::vector<std::string> const& args)
1717 if ( args.size() < 6 )
1719 this->SetError("called with incorrect number of arguments");
1720 return false;
1723 // Construct a file installer object.
1724 cmFileInstaller installer(this, this->Makefile);
1726 std::string rename = "";
1727 std::string destination = "";
1729 std::vector<std::string> files;
1730 int itype = cmTarget::INSTALL_FILES;
1732 std::map<cmStdString, const char*> properties;
1733 bool optional = false;
1734 bool result = this->ParseInstallArgs(args, installer, properties,
1735 itype, rename, destination, files,
1736 optional);
1737 if (result == true)
1739 result = this->DoInstall(installer,
1740 itype, rename, destination, files, optional);
1742 return result;
1745 //----------------------------------------------------------------------------
1746 bool cmFileCommand::ParseInstallArgs(std::vector<std::string> const& args,
1747 cmFileInstaller& installer,
1748 std::map<cmStdString, const char*>& properties,
1749 int& itype,
1750 std::string& rename,
1751 std::string& destination,
1752 std::vector<std::string>& files,
1753 bool& optional)
1755 std::string stype = "FILES";
1756 enum Doing { DoingNone, DoingFiles, DoingProperties,
1757 DoingPermissionsFile, DoingPermissionsDir,
1758 DoingPermissionsMatch, DoingSelf24 };
1759 Doing doing = DoingNone;
1760 bool use_given_permissions_file = false;
1761 bool use_given_permissions_dir = false;
1762 bool use_source_permissions = false;
1763 mode_t permissions_file = 0;
1764 mode_t permissions_dir = 0;
1766 cmFileInstaller::MatchRule* current_match_rule = 0;
1767 std::vector<std::string>::size_type i = 0;
1768 i++; // Get rid of subcommand
1769 for ( ; i != args.size(); ++i )
1771 const std::string* cstr = &args[i];
1772 if ( *cstr == "DESTINATION" && i < args.size()-1 )
1774 if(current_match_rule)
1776 cmOStringStream e;
1777 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1778 this->SetError(e.str().c_str());
1779 return false;
1782 i++;
1783 destination = args[i];
1784 doing = DoingNone;
1786 else if ( *cstr == "TYPE" && i < args.size()-1 )
1788 if(current_match_rule)
1790 cmOStringStream e;
1791 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1792 this->SetError(e.str().c_str());
1793 return false;
1796 i++;
1797 stype = args[i];
1798 if ( args[i+1] == "OPTIONAL" )
1800 i++;
1801 optional = true;
1803 doing = DoingNone;
1805 else if ( *cstr == "RENAME" && i < args.size()-1 )
1807 if(current_match_rule)
1809 cmOStringStream e;
1810 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1811 this->SetError(e.str().c_str());
1812 return false;
1815 i++;
1816 rename = args[i];
1817 doing = DoingNone;
1819 else if ( *cstr == "REGEX" && i < args.size()-1 )
1821 i++;
1822 installer.MatchRules.push_back(cmFileInstaller::MatchRule(args[i]));
1823 current_match_rule = &*(installer.MatchRules.end()-1);
1824 if(!current_match_rule->Regex.is_valid())
1826 cmOStringStream e;
1827 e << "INSTALL could not compile REGEX \"" << args[i] << "\".";
1828 this->SetError(e.str().c_str());
1829 return false;
1831 doing = DoingNone;
1833 else if ( *cstr == "EXCLUDE" )
1835 // Add this property to the current match rule.
1836 if(!current_match_rule)
1838 cmOStringStream e;
1839 e << "INSTALL does not allow \""
1840 << *cstr << "\" before a REGEX is given.";
1841 this->SetError(e.str().c_str());
1842 return false;
1844 current_match_rule->Properties.Exclude = true;
1845 doing = DoingPermissionsMatch;
1847 else if ( *cstr == "PROPERTIES" )
1849 if(current_match_rule)
1851 cmOStringStream e;
1852 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1853 this->SetError(e.str().c_str());
1854 return false;
1857 doing = DoingProperties;
1859 else if ( *cstr == "PERMISSIONS" )
1861 if(current_match_rule)
1863 doing = DoingPermissionsMatch;
1865 else
1867 doing = DoingPermissionsFile;
1868 use_given_permissions_file = true;
1871 else if ( *cstr == "DIR_PERMISSIONS" )
1873 if(current_match_rule)
1875 cmOStringStream e;
1876 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1877 this->SetError(e.str().c_str());
1878 return false;
1881 use_given_permissions_dir = true;
1882 doing = DoingPermissionsDir;
1884 else if ( *cstr == "USE_SOURCE_PERMISSIONS" )
1886 if(current_match_rule)
1888 cmOStringStream e;
1889 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1890 this->SetError(e.str().c_str());
1891 return false;
1894 doing = DoingNone;
1895 use_source_permissions = true;
1897 else if ( *cstr == "FILES_MATCHING" )
1899 if(current_match_rule)
1901 cmOStringStream e;
1902 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1903 this->SetError(e.str().c_str());
1904 return false;
1907 doing = DoingNone;
1908 installer.MatchlessFiles = false;
1910 else if ( *cstr == "COMPONENTS" )
1912 if(this->Makefile->IsOn("CMAKE_INSTALL_SELF_2_4"))
1914 // When CMake 2.4 builds this CMake version we need to support
1915 // the install scripts it generates since it asks this CMake
1916 // to install itself using the rules it generated.
1917 doing = DoingSelf24;
1918 continue;
1920 cmOStringStream e;
1921 e << "INSTALL called with old-style COMPONENTS argument. "
1922 << "This script was generated with an older version of CMake. "
1923 << "Re-run this cmake version on your build tree.";
1924 this->SetError(e.str().c_str());
1925 return false;
1927 else if ( *cstr == "CONFIGURATIONS" )
1929 cmOStringStream e;
1930 e << "INSTALL called with old-style CONFIGURATIONS argument. "
1931 << "This script was generated with an older version of CMake. "
1932 << "Re-run this cmake version on your build tree.";
1933 this->SetError(e.str().c_str());
1934 return false;
1936 else if(*cstr == "FILES" && doing != DoingFiles)
1938 if(current_match_rule)
1940 cmOStringStream e;
1941 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1942 this->SetError(e.str().c_str());
1943 return false;
1946 doing = DoingFiles;
1948 else if(doing == DoingProperties && i < args.size()-1)
1950 properties[args[i]] = args[i+1].c_str();
1951 i++;
1953 else if(doing == DoingFiles)
1955 files.push_back(*cstr);
1957 else if(doing == DoingPermissionsFile)
1959 if(!installer.CheckPermissions(args[i], permissions_file))
1961 return false;
1964 else if(doing == DoingPermissionsDir)
1966 if(!installer.CheckPermissions(args[i], permissions_dir))
1968 return false;
1971 else if(doing == DoingPermissionsMatch)
1973 if(!installer.CheckPermissions(
1974 args[i], current_match_rule->Properties.Permissions))
1976 return false;
1979 else if(doing == DoingSelf24)
1981 // Ignore these arguments for compatibility. This should be
1982 // reached only when CMake 2.4 is installing the current
1983 // CMake. It can be removed when CMake 2.6 or higher is
1984 // required to build CMake.
1986 else
1988 this->SetError("called with inappropriate arguments");
1989 return false;
1993 // now check and postprocess what has been parsed
1994 if ( files.size() == 0 )
1996 // nothing to do, no files were listed.
1997 // if this is handled as error, INSTALL_FILES() creates an invalid
1998 // cmake_install.cmake script with no FILES() arguments if no files were
1999 // given to INSTALL_FILES(). This was accepted with CMake 2.4.x.
2000 return true;
2003 // Check rename form.
2004 if(!rename.empty())
2006 if(itype != cmTarget::INSTALL_FILES &&
2007 itype != cmTarget::INSTALL_PROGRAMS)
2009 this->SetError("INSTALL option RENAME may be used only with "
2010 "FILES or PROGRAMS.");
2011 return false;
2013 if(files.size() > 1)
2015 this->SetError("INSTALL option RENAME may be used only with "
2016 "one file.");
2017 return false;
2021 if (this->HandleInstallDestination(installer, destination) == false)
2023 return false;
2026 if(properties.find("VERSION") != properties.end())
2028 cmOStringStream e;
2029 e << "INSTALL called with old-style VERSION property. "
2030 << "This script was generated with an older version of CMake. "
2031 << "Re-run this cmake version on your build tree.";
2032 this->SetError(e.str().c_str());
2033 return false;
2035 if(properties.find("SOVERSION") != properties.end())
2037 cmOStringStream e;
2038 e << "INSTALL called with old-style SOVERSION property. "
2039 << "This script was generated with an older version of CMake. "
2040 << "Re-run this cmake version on your build tree.";
2041 this->SetError(e.str().c_str());
2042 return false;
2045 this->GetTargetTypeFromString(stype, itype);
2047 this->HandleInstallPermissions(installer,
2048 permissions_file,
2049 permissions_dir,
2050 itype,
2051 use_given_permissions_file,
2052 use_given_permissions_dir,
2053 use_source_permissions);
2055 return true;
2058 //----------------------------------------------------------------------------
2059 bool cmFileCommand::DoInstall( cmFileInstaller& installer,
2060 const int itype,
2061 const std::string& rename,
2062 const std::string& destination,
2063 const std::vector<std::string>& files,
2064 const bool optional)
2066 typedef std::set<cmStdString>::const_iterator iter_type;
2068 // Check whether files should be copied always or only if they have
2069 // changed.
2070 bool copy_always =
2071 cmSystemTools::IsOn(cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS"));
2073 // Handle each file listed.
2074 for (std::vector<std::string>::size_type i = 0; i < files.size(); i ++ )
2076 // Split the input file into its directory and name components.
2077 std::vector<std::string> fromPathComponents;
2078 cmSystemTools::SplitPath(files[i].c_str(), fromPathComponents);
2079 std::string fromName = *(fromPathComponents.end()-1);
2080 std::string fromDir = cmSystemTools::JoinPath(fromPathComponents.begin(),
2081 fromPathComponents.end()-1);
2083 // Compute the full path to the destination file.
2084 std::string toFile = destination;
2085 std::string const& toName = rename.empty()? fromName : rename;
2086 if(!toName.empty())
2088 toFile += "/";
2089 toFile += toName;
2092 // Construct the full path to the source file. The file name may
2093 // have been changed above.
2094 std::string fromFile = fromDir;
2095 if(!fromName.empty())
2097 fromFile += "/";
2098 fromFile += fromName;
2101 std::string message;
2102 if(!cmSystemTools::SameFile(fromFile.c_str(), toFile.c_str()))
2104 if(itype == cmTarget::INSTALL_DIRECTORY &&
2105 (fromFile.empty() ||
2106 cmSystemTools::FileIsDirectory(fromFile.c_str())))
2108 // Try installing this directory.
2109 if(!installer.InstallDirectory(fromFile.c_str(), toFile.c_str(),
2110 copy_always))
2112 return false;
2115 else if(cmSystemTools::FileExists(fromFile.c_str()))
2117 // Install this file.
2118 if(!installer.InstallFile(fromFile.c_str(), toFile.c_str(),
2119 copy_always))
2121 return false;
2124 else if(!optional)
2126 // The input file does not exist and installation is not optional.
2127 cmOStringStream e;
2128 e << "INSTALL cannot find file \"" << fromFile << "\" to install.";
2129 this->SetError(e.str().c_str());
2130 return false;
2135 return true;
2138 //----------------------------------------------------------------------------
2139 bool cmFileCommand::HandleRelativePathCommand(
2140 std::vector<std::string> const& args)
2142 if(args.size() != 4 )
2144 this->SetError("called with incorrect number of arguments");
2145 return false;
2148 const std::string& outVar = args[1];
2149 const std::string& directoryName = args[2];
2150 const std::string& fileName = args[3];
2152 if(!cmSystemTools::FileIsFullPath(directoryName.c_str()))
2154 std::string errstring =
2155 "RelativePath must be passed a full path to the directory: "
2156 + directoryName;
2157 this->SetError(errstring.c_str());
2158 return false;
2160 if(!cmSystemTools::FileIsFullPath(fileName.c_str()))
2162 std::string errstring =
2163 "RelativePath must be passed a full path to the file: "
2164 + fileName;
2165 this->SetError(errstring.c_str());
2166 return false;
2169 std::string res = cmSystemTools::RelativePath(directoryName.c_str(),
2170 fileName.c_str());
2171 this->Makefile->AddDefinition(outVar.c_str(),
2172 res.c_str());
2173 return true;
2177 //----------------------------------------------------------------------------
2178 bool cmFileCommand::HandleRemove(std::vector<std::string> const& args,
2179 bool recurse)
2182 std::string message;
2183 std::vector<std::string>::const_iterator i = args.begin();
2185 i++; // Get rid of subcommand
2186 for(;i != args.end(); ++i)
2188 std::string fileName = *i;
2189 if(!cmsys::SystemTools::FileIsFullPath(fileName.c_str()))
2191 fileName = this->Makefile->GetCurrentDirectory();
2192 fileName += "/" + *i;
2195 if(cmSystemTools::FileIsDirectory(fileName.c_str()) && recurse)
2197 cmSystemTools::RemoveADirectory(fileName.c_str());
2199 else
2201 cmSystemTools::RemoveFile(fileName.c_str());
2204 return true;
2207 //----------------------------------------------------------------------------
2208 bool cmFileCommand::HandleCMakePathCommand(std::vector<std::string>
2209 const& args,
2210 bool nativePath)
2212 std::vector<std::string>::const_iterator i = args.begin();
2213 if(args.size() != 3)
2215 this->SetError("FILE(SYSTEM_PATH ENV result) must be called with "
2216 "only three arguments.");
2217 return false;
2219 i++; // Get rid of subcommand
2220 #if defined(_WIN32) && !defined(__CYGWIN__)
2221 char pathSep = ';';
2222 #else
2223 char pathSep = ':';
2224 #endif
2225 std::vector<cmsys::String> path = cmSystemTools::SplitString(i->c_str(),
2226 pathSep);
2227 i++;
2228 const char* var = i->c_str();
2229 std::string value;
2230 for(std::vector<cmsys::String>::iterator j = path.begin();
2231 j != path.end(); ++j)
2233 if(j != path.begin())
2235 value += ";";
2237 if(!nativePath)
2239 cmSystemTools::ConvertToUnixSlashes(*j);
2241 else
2243 *j = cmSystemTools::ConvertToOutputPath(j->c_str());
2244 // remove double quotes in the path
2245 cmsys::String& s = *j;
2247 if(s.size() > 1 && s[0] == '\"' && s[s.size()-1] == '\"')
2249 s = s.substr(1,s.size()-2);
2252 value += *j;
2254 this->Makefile->AddDefinition(var, value.c_str());
2255 return true;
2257 #if defined(CMAKE_BUILD_WITH_CMAKE)
2259 // Stuff for curl download
2260 typedef std::vector<char> cmFileCommandVectorOfChar;
2261 namespace{
2262 size_t
2263 cmFileCommandWriteMemoryCallback(void *ptr, size_t size, size_t nmemb,
2264 void *data)
2266 register int realsize = (int)(size * nmemb);
2267 std::ofstream* fout = static_cast<std::ofstream*>(data);
2268 const char* chPtr = static_cast<char*>(ptr);
2269 fout->write(chPtr, realsize);
2270 return realsize;
2273 static size_t
2274 cmFileCommandCurlDebugCallback(CURL *, curl_infotype, char *chPtr,
2275 size_t size, void *data)
2277 cmFileCommandVectorOfChar *vec
2278 = static_cast<cmFileCommandVectorOfChar*>(data);
2279 vec->insert(vec->end(), chPtr, chPtr + size);
2281 return size;
2287 #endif
2289 bool
2290 cmFileCommand::HandleDownloadCommand(std::vector<std::string>
2291 const& args)
2293 #if defined(CMAKE_BUILD_WITH_CMAKE)
2294 std::vector<std::string>::const_iterator i = args.begin();
2295 if(args.size() < 3)
2297 this->SetError("FILE(DOWNLOAD url file) must be called with "
2298 "at least three arguments.");
2299 return false;
2301 i++; // Get rid of subcommand
2302 std::string url = *i;
2303 i++;
2304 std::string file = *i;
2305 i++;
2306 double timeout = 0;
2307 std::string verboseLog;
2308 std::string statusVar;
2309 while(i != args.end())
2311 if(*i == "TIMEOUT")
2313 i++;
2314 if(i != args.end())
2316 timeout = atof(i->c_str());
2318 else
2320 this->SetError("FILE(DOWNLOAD url file TIMEOUT time) missing "
2321 "time for TIMEOUT.");
2322 return false;
2325 else if(*i == "LOG")
2327 i++;
2328 if( i == args.end())
2330 this->SetError("FILE(DOWNLOAD url file LOG VAR) missing "
2331 "VAR for LOG.");
2332 return false;
2334 verboseLog = *i;
2336 else if(*i == "STATUS")
2338 i++;
2339 if( i == args.end())
2341 this->SetError("FILE(DOWNLOAD url file STATUS VAR) missing "
2342 "VAR for STATUS.");
2343 return false;
2345 statusVar = *i;
2347 i++;
2350 std::string dir = cmSystemTools::GetFilenamePath(file.c_str());
2351 if(!cmSystemTools::FileExists(dir.c_str()) &&
2352 !cmSystemTools::MakeDirectory(dir.c_str()))
2354 std::string errstring = "FILE(DOWNLOAD ) error; cannot create directory: "
2355 + dir + ". Maybe need administrative privileges.";
2356 this->SetError(errstring.c_str());
2357 return false;
2360 std::ofstream fout(file.c_str(), std::ios::binary);
2361 if(!fout)
2363 this->SetError("FILE(DOWNLOAD url file TIMEOUT time) can not open "
2364 "file for write.");
2365 return false;
2367 CURL *curl;
2368 curl_global_init(CURL_GLOBAL_DEFAULT);
2369 curl = curl_easy_init();
2370 if(!curl)
2372 this->SetError("FILE(DOWNLOAD ) error "
2373 "initializing curl.");
2374 return false;
2377 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
2378 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
2379 cmFileCommandWriteMemoryCallback);
2380 curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
2381 cmFileCommandCurlDebugCallback);
2382 cmFileCommandVectorOfChar chunkDebug;
2383 ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&fout);
2384 ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
2385 if(verboseLog.size())
2387 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
2389 if(timeout > 0)
2391 curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout );
2393 CURLcode res = curl_easy_perform(curl);
2394 /* always cleanup */
2395 curl_easy_cleanup(curl);
2396 if(statusVar.size())
2398 cmOStringStream result;
2399 result << (int)res << ";\"" << curl_easy_strerror(res) << "\"";
2400 this->Makefile->AddDefinition(statusVar.c_str(),
2401 result.str().c_str());
2403 curl_global_cleanup();
2404 if(chunkDebug.size())
2406 chunkDebug.push_back(0);
2407 if(CURLE_OPERATION_TIMEOUTED == res)
2409 std::string output = &*chunkDebug.begin();
2411 if(verboseLog.size())
2413 this->Makefile->AddDefinition(verboseLog.c_str(),
2414 &*chunkDebug.begin());
2418 this->Makefile->AddDefinition(verboseLog.c_str(),
2419 &*chunkDebug.begin());
2421 return true;
2422 #else
2423 this->SetError("FILE(DOWNLOAD ) "
2424 "not supported in bootstrap cmake ");
2425 return false;
2426 #endif