Fix typo in name
[cmake.git] / Source / cmFileCommand.cxx
blobeb33cf056c0af15f09cba1415231d2cfb8217f73
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmFileCommand.cxx,v $
5 Language: C++
6 Date: $Date: 2009-09-11 12:18:03 $
7 Version: $Revision: 1.136 $
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 == "RENAME" )
105 return this->HandleRename(args);
107 else if ( subCommand == "REMOVE" )
109 return this->HandleRemove(args, false);
111 else if ( subCommand == "REMOVE_RECURSE" )
113 return this->HandleRemove(args, true);
115 else if ( subCommand == "COPY" )
117 return this->HandleCopyCommand(args);
119 else if ( subCommand == "INSTALL" )
121 return this->HandleInstallCommand(args);
123 else if ( subCommand == "DIFFERENT" )
125 return this->HandleDifferentCommand(args);
127 else if ( subCommand == "RPATH_CHANGE" || subCommand == "CHRPATH" )
129 return this->HandleRPathChangeCommand(args);
131 else if ( subCommand == "RPATH_CHECK" )
133 return this->HandleRPathCheckCommand(args);
135 else if ( subCommand == "RPATH_REMOVE" )
137 return this->HandleRPathRemoveCommand(args);
139 else if ( subCommand == "RELATIVE_PATH" )
141 return this->HandleRelativePathCommand(args);
143 else if ( subCommand == "TO_CMAKE_PATH" )
145 return this->HandleCMakePathCommand(args, false);
147 else if ( subCommand == "TO_NATIVE_PATH" )
149 return this->HandleCMakePathCommand(args, true);
152 std::string e = "does not recognize sub-command "+subCommand;
153 this->SetError(e.c_str());
154 return false;
157 //----------------------------------------------------------------------------
158 bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args,
159 bool append)
161 std::string message;
162 std::vector<std::string>::const_iterator i = args.begin();
164 i++; // Get rid of subcommand
166 std::string fileName = *i;
167 if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
169 fileName = this->Makefile->GetCurrentDirectory();
170 fileName += "/" + *i;
173 i++;
175 for(;i != args.end(); ++i)
177 message += *i;
179 if ( !this->Makefile->CanIWriteThisFile(fileName.c_str()) )
181 std::string e
182 = "attempted to write a file: " + fileName +
183 " into a source directory.";
184 this->SetError(e.c_str());
185 cmSystemTools::SetFatalErrorOccured();
186 return false;
188 std::string dir = cmSystemTools::GetFilenamePath(fileName);
189 cmSystemTools::MakeDirectory(dir.c_str());
191 mode_t mode =
192 #if defined( _MSC_VER ) || defined( __MINGW32__ )
193 S_IREAD | S_IWRITE
194 #elif defined( __BORLANDC__ )
195 S_IRUSR | S_IWUSR
196 #else
197 S_IRUSR | S_IWUSR |
198 S_IRGRP |
199 S_IROTH
200 #endif
203 // Set permissions to writable
204 if ( cmSystemTools::GetPermissions(fileName.c_str(), mode) )
206 cmSystemTools::SetPermissions(fileName.c_str(),
207 #if defined( _MSC_VER ) || defined( __MINGW32__ )
208 S_IREAD | S_IWRITE
209 #else
210 S_IRUSR | S_IWUSR
211 #endif
214 // If GetPermissions fails, pretend like it is ok. File open will fail if
215 // the file is not writable
216 std::ofstream file(fileName.c_str(), append?std::ios::app: std::ios::out);
217 if ( !file )
219 std::string error = "Internal CMake error when trying to open file: ";
220 error += fileName.c_str();
221 error += " for writing.";
222 this->SetError(error.c_str());
223 return false;
225 file << message;
226 file.close();
227 cmSystemTools::SetPermissions(fileName.c_str(), mode);
228 return true;
231 //----------------------------------------------------------------------------
232 bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args)
234 if ( args.size() < 3 )
236 this->SetError("READ must be called with at least two additional "
237 "arguments");
238 return false;
241 cmCommandArgumentsHelper argHelper;
242 cmCommandArgumentGroup group;
244 cmCAString readArg (&argHelper, "READ");
245 cmCAString fileNameArg (&argHelper, 0);
246 cmCAString resultArg (&argHelper, 0);
248 cmCAString offsetArg (&argHelper, "OFFSET", &group);
249 cmCAString limitArg (&argHelper, "LIMIT", &group);
250 cmCAEnabler hexOutputArg (&argHelper, "HEX", &group);
251 readArg.Follows(0);
252 fileNameArg.Follows(&readArg);
253 resultArg.Follows(&fileNameArg);
254 group.Follows(&resultArg);
255 argHelper.Parse(&args, 0);
257 std::string fileName = fileNameArg.GetString();
258 if ( !cmsys::SystemTools::FileIsFullPath(fileName.c_str()) )
260 fileName = this->Makefile->GetCurrentDirectory();
261 fileName += "/" + fileNameArg.GetString();
264 std::string variable = resultArg.GetString();
266 // Open the specified file.
267 #if defined(_WIN32) || defined(__CYGWIN__)
268 std::ifstream file(fileName.c_str(), std::ios::in |
269 (hexOutputArg.IsEnabled() ? std::ios::binary : std::ios::in));
270 #else
271 std::ifstream file(fileName.c_str(), std::ios::in);
272 #endif
274 if ( !file )
276 std::string error = "Internal CMake error when trying to open file: ";
277 error += fileName.c_str();
278 error += " for reading.";
279 this->SetError(error.c_str());
280 return false;
283 // is there a limit?
284 long sizeLimit = -1;
285 if (limitArg.GetString().size() > 0)
287 sizeLimit = atoi(limitArg.GetCString());
290 // is there an offset?
291 long offset = 0;
292 if (offsetArg.GetString().size() > 0)
294 offset = atoi(offsetArg.GetCString());
297 file.seekg(offset);
299 std::string output;
301 if (hexOutputArg.IsEnabled())
303 // Convert part of the file into hex code
304 char c;
305 while((sizeLimit != 0) && (file.get(c)))
307 char hex[4];
308 sprintf(hex, "%.2x", c&0xff);
309 output += hex;
310 if (sizeLimit > 0)
312 sizeLimit--;
316 else
318 std::string line;
319 bool has_newline = false;
320 while (sizeLimit != 0 &&
321 cmSystemTools::GetLineFromStream(file, line, &has_newline,
322 sizeLimit) )
324 if (sizeLimit > 0)
326 sizeLimit = sizeLimit - static_cast<long>(line.size());
327 if (has_newline)
329 sizeLimit--;
331 if (sizeLimit < 0)
333 sizeLimit = 0;
336 output += line;
337 if ( has_newline )
339 output += "\n";
343 this->Makefile->AddDefinition(variable.c_str(), output.c_str());
344 return true;
347 //----------------------------------------------------------------------------
348 bool cmFileCommand::HandleStringsCommand(std::vector<std::string> const& args)
350 if(args.size() < 3)
352 this->SetError("STRINGS requires a file name and output variable");
353 return false;
356 // Get the file to read.
357 std::string fileName = args[1];
358 if(!cmsys::SystemTools::FileIsFullPath(fileName.c_str()))
360 fileName = this->Makefile->GetCurrentDirectory();
361 fileName += "/" + args[1];
364 // Get the variable in which to store the results.
365 std::string outVar = args[2];
367 // Parse the options.
368 enum { arg_none,
369 arg_limit_input,
370 arg_limit_output,
371 arg_limit_count,
372 arg_length_minimum,
373 arg_length_maximum,
374 arg__maximum,
375 arg_regex };
376 unsigned int minlen = 0;
377 unsigned int maxlen = 0;
378 int limit_input = -1;
379 int limit_output = -1;
380 unsigned int limit_count = 0;
381 cmsys::RegularExpression regex;
382 bool have_regex = false;
383 bool newline_consume = false;
384 bool hex_conversion_enabled = true;
385 int arg_mode = arg_none;
386 for(unsigned int i=3; i < args.size(); ++i)
388 if(args[i] == "LIMIT_INPUT")
390 arg_mode = arg_limit_input;
392 else if(args[i] == "LIMIT_OUTPUT")
394 arg_mode = arg_limit_output;
396 else if(args[i] == "LIMIT_COUNT")
398 arg_mode = arg_limit_count;
400 else if(args[i] == "LENGTH_MINIMUM")
402 arg_mode = arg_length_minimum;
404 else if(args[i] == "LENGTH_MAXIMUM")
406 arg_mode = arg_length_maximum;
408 else if(args[i] == "REGEX")
410 arg_mode = arg_regex;
412 else if(args[i] == "NEWLINE_CONSUME")
414 newline_consume = true;
415 arg_mode = arg_none;
417 else if(args[i] == "NO_HEX_CONVERSION")
419 hex_conversion_enabled = false;
420 arg_mode = arg_none;
422 else if(arg_mode == arg_limit_input)
424 if(sscanf(args[i].c_str(), "%d", &limit_input) != 1 ||
425 limit_input < 0)
427 cmOStringStream e;
428 e << "STRINGS option LIMIT_INPUT value \""
429 << args[i] << "\" is not an unsigned integer.";
430 this->SetError(e.str().c_str());
431 return false;
433 arg_mode = arg_none;
435 else if(arg_mode == arg_limit_output)
437 if(sscanf(args[i].c_str(), "%d", &limit_output) != 1 ||
438 limit_output < 0)
440 cmOStringStream e;
441 e << "STRINGS option LIMIT_OUTPUT value \""
442 << args[i] << "\" is not an unsigned integer.";
443 this->SetError(e.str().c_str());
444 return false;
446 arg_mode = arg_none;
448 else if(arg_mode == arg_limit_count)
450 int count;
451 if(sscanf(args[i].c_str(), "%d", &count) != 1 || count < 0)
453 cmOStringStream e;
454 e << "STRINGS option LIMIT_COUNT value \""
455 << args[i] << "\" is not an unsigned integer.";
456 this->SetError(e.str().c_str());
457 return false;
459 limit_count = count;
460 arg_mode = arg_none;
462 else if(arg_mode == arg_length_minimum)
464 int len;
465 if(sscanf(args[i].c_str(), "%d", &len) != 1 || len < 0)
467 cmOStringStream e;
468 e << "STRINGS option LENGTH_MINIMUM value \""
469 << args[i] << "\" is not an unsigned integer.";
470 this->SetError(e.str().c_str());
471 return false;
473 minlen = len;
474 arg_mode = arg_none;
476 else if(arg_mode == arg_length_maximum)
478 int len;
479 if(sscanf(args[i].c_str(), "%d", &len) != 1 || len < 0)
481 cmOStringStream e;
482 e << "STRINGS option LENGTH_MAXIMUM value \""
483 << args[i] << "\" is not an unsigned integer.";
484 this->SetError(e.str().c_str());
485 return false;
487 maxlen = len;
488 arg_mode = arg_none;
490 else if(arg_mode == arg_regex)
492 if(!regex.compile(args[i].c_str()))
494 cmOStringStream e;
495 e << "STRINGS option REGEX value \""
496 << args[i] << "\" could not be compiled.";
497 this->SetError(e.str().c_str());
498 return false;
500 have_regex = true;
501 arg_mode = arg_none;
503 else
505 cmOStringStream e;
506 e << "STRINGS given unknown argument \""
507 << args[i] << "\"";
508 this->SetError(e.str().c_str());
509 return false;
513 if (hex_conversion_enabled)
515 // TODO: should work without temp file, but just on a memory buffer
516 std::string binaryFileName = this->Makefile->GetCurrentOutputDirectory();
517 binaryFileName += cmake::GetCMakeFilesDirectory();
518 binaryFileName += "/FileCommandStringsBinaryFile";
519 if(cmHexFileConverter::TryConvert(fileName.c_str(),binaryFileName.c_str()))
521 fileName = binaryFileName;
525 // Open the specified file.
526 #if defined(_WIN32) || defined(__CYGWIN__)
527 std::ifstream fin(fileName.c_str(), std::ios::in | std::ios::binary);
528 #else
529 std::ifstream fin(fileName.c_str(), std::ios::in);
530 #endif
531 if(!fin)
533 cmOStringStream e;
534 e << "STRINGS file \"" << fileName << "\" cannot be read.";
535 this->SetError(e.str().c_str());
536 return false;
539 // Parse strings out of the file.
540 int output_size = 0;
541 std::vector<std::string> strings;
542 std::string s;
543 int c;
544 while((!limit_count || strings.size() < limit_count) &&
545 (limit_input < 0 || static_cast<int>(fin.tellg()) < limit_input) &&
546 (c = fin.get(), fin))
548 if(c == '\0')
550 // A terminating null character has been found. Check if the
551 // current string matches the requirements. Since it was
552 // terminated by a null character, we require that the length be
553 // at least one no matter what the user specified.
554 if(s.length() >= minlen && s.length() >= 1 &&
555 (!have_regex || regex.find(s.c_str())))
557 output_size += static_cast<int>(s.size()) + 1;
558 if(limit_output >= 0 && output_size >= limit_output)
560 s = "";
561 break;
563 strings.push_back(s);
566 // Reset the string to empty.
567 s = "";
569 else if(c == '\n' && !newline_consume)
571 // The current line has been terminated. Check if the current
572 // string matches the requirements. The length may now be as
573 // low as zero since blank lines are allowed.
574 if(s.length() >= minlen &&
575 (!have_regex || regex.find(s.c_str())))
577 output_size += static_cast<int>(s.size()) + 1;
578 if(limit_output >= 0 && output_size >= limit_output)
580 s = "";
581 break;
583 strings.push_back(s);
586 // Reset the string to empty.
587 s = "";
589 else if(c == '\r')
591 // Ignore CR character to make output always have UNIX newlines.
593 else if((c >= 0x20 && c < 0x7F) || c == '\t' || c == '\f' ||
594 (c == '\n' && newline_consume))
596 // This is an ASCII character that may be part of a string.
597 s += c;
599 else
601 // This is a non-string character. Reset the string to emtpy.
602 s = "";
605 // Terminate a string if the maximum length is reached.
606 if(maxlen > 0 && s.size() == maxlen)
608 if(s.length() >= minlen &&
609 (!have_regex || regex.find(s.c_str())))
611 output_size += static_cast<int>(s.size()) + 1;
612 if(limit_output >= 0 && output_size >= limit_output)
614 s = "";
615 break;
617 strings.push_back(s);
619 s = "";
623 // If there is a non-empty current string we have hit the end of the
624 // input file or the input size limit. Check if the current string
625 // matches the requirements.
626 if((!limit_count || strings.size() < limit_count) &&
627 !s.empty() && s.length() >= minlen &&
628 (!have_regex || regex.find(s.c_str())))
630 output_size += static_cast<int>(s.size()) + 1;
631 if(limit_output < 0 || output_size < limit_output)
633 strings.push_back(s);
637 // Encode the result in a CMake list.
638 const char* sep = "";
639 std::string output;
640 for(std::vector<std::string>::const_iterator si = strings.begin();
641 si != strings.end(); ++si)
643 // Separate the strings in the output to make it a list.
644 output += sep;
645 sep = ";";
647 // Store the string in the output, but escape semicolons to
648 // make sure it is a list.
649 std::string const& sr = *si;
650 for(unsigned int i=0; i < sr.size(); ++i)
652 if(sr[i] == ';')
654 output += '\\';
656 output += sr[i];
660 // Save the output in a makefile variable.
661 this->Makefile->AddDefinition(outVar.c_str(), output.c_str());
662 return true;
665 //----------------------------------------------------------------------------
666 bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
667 bool recurse)
669 if ( args.size() < 2 )
671 this->SetError("GLOB requires at least a variable name");
672 return false;
675 std::vector<std::string>::const_iterator i = args.begin();
677 i++; // Get rid of subcommand
679 std::string variable = *i;
680 i++;
681 cmsys::Glob g;
682 g.SetRecurse(recurse);
684 bool explicitFollowSymlinks = false;
685 cmPolicies::PolicyStatus status =
686 this->Makefile->GetPolicyStatus(cmPolicies::CMP0009);
687 if(recurse)
689 switch(status)
691 case cmPolicies::NEW:
692 g.RecurseThroughSymlinksOff();
693 break;
694 case cmPolicies::OLD:
695 case cmPolicies::WARN:
696 case cmPolicies::REQUIRED_IF_USED:
697 case cmPolicies::REQUIRED_ALWAYS:
698 g.RecurseThroughSymlinksOn();
699 break;
703 std::string output = "";
704 bool first = true;
705 for ( ; i != args.end(); ++i )
707 if ( recurse && (*i == "FOLLOW_SYMLINKS") )
709 explicitFollowSymlinks = true;
710 g.RecurseThroughSymlinksOn();
711 ++i;
712 if ( i == args.end() )
714 this->SetError(
715 "GLOB_RECURSE requires a glob expression after FOLLOW_SYMLINKS");
716 return false;
720 if ( *i == "RELATIVE" )
722 ++i; // skip RELATIVE
723 if ( i == args.end() )
725 this->SetError("GLOB requires a directory after the RELATIVE tag");
726 return false;
728 g.SetRelative(i->c_str());
729 ++i;
730 if(i == args.end())
732 this->SetError("GLOB requires a glob expression after the directory");
733 return false;
737 if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
739 std::string expr = this->Makefile->GetCurrentDirectory();
740 // Handle script mode
741 if ( expr.size() > 0 )
743 expr += "/" + *i;
744 g.FindFiles(expr);
746 else
748 g.FindFiles(*i);
751 else
753 g.FindFiles(*i);
756 std::vector<std::string>::size_type cc;
757 std::vector<std::string>& files = g.GetFiles();
758 for ( cc = 0; cc < files.size(); cc ++ )
760 if ( !first )
762 output += ";";
764 output += files[cc];
765 first = false;
769 if(recurse && !explicitFollowSymlinks)
771 switch (status)
773 case cmPolicies::NEW:
774 // Correct behavior, yay!
775 break;
776 case cmPolicies::OLD:
777 // Probably not really the expected behavior, but the author explicitly
778 // asked for the old behavior... no warning.
779 case cmPolicies::WARN:
780 // Possibly unexpected old behavior *and* we actually traversed
781 // symlinks without being explicitly asked to: warn the author.
782 if(g.GetFollowedSymlinkCount() != 0)
784 this->Makefile->IssueMessage(cmake::AUTHOR_WARNING,
785 this->Makefile->GetPolicies()->
786 GetPolicyWarning(cmPolicies::CMP0009));
788 break;
789 case cmPolicies::REQUIRED_IF_USED:
790 case cmPolicies::REQUIRED_ALWAYS:
791 this->SetError("policy CMP0009 error");
792 this->Makefile->IssueMessage(cmake::FATAL_ERROR,
793 this->Makefile->GetPolicies()->
794 GetRequiredPolicyError(cmPolicies::CMP0009));
795 return false;
799 this->Makefile->AddDefinition(variable.c_str(), output.c_str());
800 return true;
803 //----------------------------------------------------------------------------
804 bool cmFileCommand::HandleMakeDirectoryCommand(
805 std::vector<std::string> const& args)
807 if(args.size() < 2 )
809 this->SetError("called with incorrect number of arguments");
810 return false;
813 std::vector<std::string>::const_iterator i = args.begin();
815 i++; // Get rid of subcommand
817 std::string expr;
818 for ( ; i != args.end(); ++i )
820 const std::string* cdir = &(*i);
821 if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
823 expr = this->Makefile->GetCurrentDirectory();
824 expr += "/" + *i;
825 cdir = &expr;
827 if ( !this->Makefile->CanIWriteThisFile(cdir->c_str()) )
829 std::string e = "attempted to create a directory: " + *cdir
830 + " into a source directory.";
831 this->SetError(e.c_str());
832 cmSystemTools::SetFatalErrorOccured();
833 return false;
835 if ( !cmSystemTools::MakeDirectory(cdir->c_str()) )
837 std::string error = "problem creating directory: " + *cdir;
838 this->SetError(error.c_str());
839 return false;
842 return true;
845 //----------------------------------------------------------------------------
846 bool
847 cmFileCommand::HandleDifferentCommand(std::vector<std::string> const& args)
850 FILE(DIFFERENT <variable> FILES <lhs> <rhs>)
853 // Evaluate arguments.
854 const char* file_lhs = 0;
855 const char* file_rhs = 0;
856 const char* var = 0;
857 enum Doing { DoingNone, DoingVar, DoingFileLHS, DoingFileRHS };
858 Doing doing = DoingVar;
859 for(unsigned int i=1; i < args.size(); ++i)
861 if(args[i] == "FILES")
863 doing = DoingFileLHS;
865 else if(doing == DoingVar)
867 var = args[i].c_str();
868 doing = DoingNone;
870 else if(doing == DoingFileLHS)
872 file_lhs = args[i].c_str();
873 doing = DoingFileRHS;
875 else if(doing == DoingFileRHS)
877 file_rhs = args[i].c_str();
878 doing = DoingNone;
880 else
882 cmOStringStream e;
883 e << "DIFFERENT given unknown argument " << args[i];
884 this->SetError(e.str().c_str());
885 return false;
888 if(!var)
890 this->SetError("DIFFERENT not given result variable name.");
891 return false;
893 if(!file_lhs || !file_rhs)
895 this->SetError("DIFFERENT not given FILES option with two file names.");
896 return false;
899 // Compare the files.
900 const char* result =
901 cmSystemTools::FilesDiffer(file_lhs, file_rhs)? "1" : "0";
902 this->Makefile->AddDefinition(var, result);
903 return true;
906 //----------------------------------------------------------------------------
907 // File installation helper class.
908 struct cmFileCopier
910 cmFileCopier(cmFileCommand* command, const char* name = "COPY"):
911 FileCommand(command),
912 Makefile(command->GetMakefile()),
913 Name(name),
914 Always(false),
915 MatchlessFiles(true),
916 FilePermissions(0),
917 DirPermissions(0),
918 CurrentMatchRule(0),
919 UseGivenPermissionsFile(false),
920 UseGivenPermissionsDir(false),
921 UseSourcePermissions(true),
922 Doing(DoingNone)
925 virtual ~cmFileCopier() {}
927 bool Run(std::vector<std::string> const& args);
928 protected:
930 cmFileCommand* FileCommand;
931 cmMakefile* Makefile;
932 const char* Name;
933 bool Always;
934 cmFileTimeComparison FileTimes;
936 // Whether to install a file not matching any expression.
937 bool MatchlessFiles;
939 // Permissions for files and directories installed by this object.
940 mode_t FilePermissions;
941 mode_t DirPermissions;
943 // Properties set by pattern and regex match rules.
944 struct MatchProperties
946 bool Exclude;
947 mode_t Permissions;
948 MatchProperties(): Exclude(false), Permissions(0) {}
950 struct MatchRule;
951 friend struct MatchRule;
952 struct MatchRule
954 cmsys::RegularExpression Regex;
955 MatchProperties Properties;
956 std::string RegexString;
957 MatchRule(std::string const& regex):
958 Regex(regex.c_str()), RegexString(regex) {}
960 std::vector<MatchRule> MatchRules;
962 // Get the properties from rules matching this input file.
963 MatchProperties CollectMatchProperties(const char* file)
965 // Match rules are case-insensitive on some platforms.
966 #if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
967 std::string lower = cmSystemTools::LowerCase(file);
968 file = lower.c_str();
969 #endif
971 // Collect properties from all matching rules.
972 bool matched = false;
973 MatchProperties result;
974 for(std::vector<MatchRule>::iterator mr = this->MatchRules.begin();
975 mr != this->MatchRules.end(); ++mr)
977 if(mr->Regex.find(file))
979 matched = true;
980 result.Exclude |= mr->Properties.Exclude;
981 result.Permissions |= mr->Properties.Permissions;
984 if(!matched && !this->MatchlessFiles)
986 result.Exclude = !cmSystemTools::FileIsDirectory(file);
988 return result;
991 bool SetPermissions(const char* toFile, mode_t permissions)
993 if(permissions && !cmSystemTools::SetPermissions(toFile, permissions))
995 cmOStringStream e;
996 e << this->Name << " cannot set permissions on \"" << toFile << "\"";
997 this->FileCommand->SetError(e.str().c_str());
998 return false;
1000 return true;
1003 // Translate an argument to a permissions bit.
1004 bool CheckPermissions(std::string const& arg, mode_t& permissions)
1006 if(arg == "OWNER_READ") { permissions |= mode_owner_read; }
1007 else if(arg == "OWNER_WRITE") { permissions |= mode_owner_write; }
1008 else if(arg == "OWNER_EXECUTE") { permissions |= mode_owner_execute; }
1009 else if(arg == "GROUP_READ") { permissions |= mode_group_read; }
1010 else if(arg == "GROUP_WRITE") { permissions |= mode_group_write; }
1011 else if(arg == "GROUP_EXECUTE") { permissions |= mode_group_execute; }
1012 else if(arg == "WORLD_READ") { permissions |= mode_world_read; }
1013 else if(arg == "WORLD_WRITE") { permissions |= mode_world_write; }
1014 else if(arg == "WORLD_EXECUTE") { permissions |= mode_world_execute; }
1015 else if(arg == "SETUID") { permissions |= mode_setuid; }
1016 else if(arg == "SETGID") { permissions |= mode_setgid; }
1017 else
1019 cmOStringStream e;
1020 e << this->Name << " given invalid permission \"" << arg << "\".";
1021 this->FileCommand->SetError(e.str().c_str());
1022 return false;
1024 return true;
1027 bool InstallSymlink(const char* fromFile, const char* toFile);
1028 bool InstallFile(const char* fromFile, const char* toFile,
1029 MatchProperties const& match_properties);
1030 bool InstallDirectory(const char* source, const char* destination,
1031 MatchProperties const& match_properties);
1032 virtual bool Install(const char* fromFile, const char* toFile);
1033 virtual std::string const& ToName(std::string const& fromName)
1034 { return fromName; }
1036 enum Type
1038 TypeFile,
1039 TypeDir,
1040 TypeLink
1042 virtual void ReportCopy(const char*, Type, bool) {}
1043 virtual bool ReportMissing(const char* fromFile)
1045 // The input file does not exist and installation is not optional.
1046 cmOStringStream e;
1047 e << this->Name << " cannot find \"" << fromFile << "\".";
1048 this->FileCommand->SetError(e.str().c_str());
1049 return false;
1052 MatchRule* CurrentMatchRule;
1053 bool UseGivenPermissionsFile;
1054 bool UseGivenPermissionsDir;
1055 bool UseSourcePermissions;
1056 std::string Destination;
1057 std::vector<std::string> Files;
1058 int Doing;
1060 virtual bool Parse(std::vector<std::string> const& args);
1061 enum
1063 DoingNone,
1064 DoingError,
1065 DoingDestination,
1066 DoingFiles,
1067 DoingPattern,
1068 DoingRegex,
1069 DoingPermissionsFile,
1070 DoingPermissionsDir,
1071 DoingPermissionsMatch,
1072 DoingLast1
1074 virtual bool CheckKeyword(std::string const& arg);
1075 virtual bool CheckValue(std::string const& arg);
1077 void NotBeforeMatch(std::string const& arg)
1079 cmOStringStream e;
1080 e << "option " << arg << " may not appear before PATTERN or REGEX.";
1081 this->FileCommand->SetError(e.str().c_str());
1082 this->Doing = DoingError;
1084 void NotAfterMatch(std::string const& arg)
1086 cmOStringStream e;
1087 e << "option " << arg << " may not appear after PATTERN or REGEX.";
1088 this->FileCommand->SetError(e.str().c_str());
1089 this->Doing = DoingError;
1091 virtual void DefaultFilePermissions()
1093 // Use read/write permissions.
1094 this->FilePermissions = 0;
1095 this->FilePermissions |= mode_owner_read;
1096 this->FilePermissions |= mode_owner_write;
1097 this->FilePermissions |= mode_group_read;
1098 this->FilePermissions |= mode_world_read;
1100 virtual void DefaultDirectoryPermissions()
1102 // Use read/write/executable permissions.
1103 this->DirPermissions = 0;
1104 this->DirPermissions |= mode_owner_read;
1105 this->DirPermissions |= mode_owner_write;
1106 this->DirPermissions |= mode_owner_execute;
1107 this->DirPermissions |= mode_group_read;
1108 this->DirPermissions |= mode_group_execute;
1109 this->DirPermissions |= mode_world_read;
1110 this->DirPermissions |= mode_world_execute;
1114 //----------------------------------------------------------------------------
1115 bool cmFileCopier::Parse(std::vector<std::string> const& args)
1117 this->Doing = DoingFiles;
1118 for(unsigned int i=1; i < args.size(); ++i)
1120 // Check this argument.
1121 if(!this->CheckKeyword(args[i]) &&
1122 !this->CheckValue(args[i]))
1124 cmOStringStream e;
1125 e << "called with unknown argument \"" << args[i] << "\".";
1126 this->FileCommand->SetError(e.str().c_str());
1127 return false;
1130 // Quit if an argument is invalid.
1131 if(this->Doing == DoingError)
1133 return false;
1137 // Require a destination.
1138 if(this->Destination.empty())
1140 cmOStringStream e;
1141 e << this->Name << " given no DESTINATION";
1142 this->FileCommand->SetError(e.str().c_str());
1143 return false;
1146 // If file permissions were not specified set default permissions.
1147 if(!this->UseGivenPermissionsFile && !this->UseSourcePermissions)
1149 this->DefaultFilePermissions();
1152 // If directory permissions were not specified set default permissions.
1153 if(!this->UseGivenPermissionsDir && !this->UseSourcePermissions)
1155 this->DefaultDirectoryPermissions();
1158 return true;
1161 //----------------------------------------------------------------------------
1162 bool cmFileCopier::CheckKeyword(std::string const& arg)
1164 if(arg == "DESTINATION")
1166 if(this->CurrentMatchRule)
1168 this->NotAfterMatch(arg);
1170 else
1172 this->Doing = DoingDestination;
1175 else if(arg == "PATTERN")
1177 this->Doing = DoingPattern;
1179 else if(arg == "REGEX")
1181 this->Doing = DoingRegex;
1183 else if(arg == "EXCLUDE")
1185 // Add this property to the current match rule.
1186 if(this->CurrentMatchRule)
1188 this->CurrentMatchRule->Properties.Exclude = true;
1189 this->Doing = DoingNone;
1191 else
1193 this->NotBeforeMatch(arg);
1196 else if(arg == "PERMISSIONS")
1198 if(this->CurrentMatchRule)
1200 this->Doing = DoingPermissionsMatch;
1202 else
1204 this->NotBeforeMatch(arg);
1207 else if(arg == "FILE_PERMISSIONS")
1209 if(this->CurrentMatchRule)
1211 this->NotAfterMatch(arg);
1213 else
1215 this->Doing = DoingPermissionsFile;
1216 this->UseGivenPermissionsFile = true;
1219 else if(arg == "DIRECTORY_PERMISSIONS")
1221 if(this->CurrentMatchRule)
1223 this->NotAfterMatch(arg);
1225 else
1227 this->Doing = DoingPermissionsDir;
1228 this->UseGivenPermissionsDir = true;
1231 else if(arg == "USE_SOURCE_PERMISSIONS")
1233 if(this->CurrentMatchRule)
1235 this->NotAfterMatch(arg);
1237 else
1239 this->Doing = DoingNone;
1240 this->UseSourcePermissions = true;
1243 else if(arg == "NO_SOURCE_PERMISSIONS")
1245 if(this->CurrentMatchRule)
1247 this->NotAfterMatch(arg);
1249 else
1251 this->Doing = DoingNone;
1252 this->UseSourcePermissions = false;
1255 else if(arg == "FILES_MATCHING")
1257 if(this->CurrentMatchRule)
1259 this->NotAfterMatch(arg);
1261 else
1263 this->Doing = DoingNone;
1264 this->MatchlessFiles = false;
1267 else
1269 return false;
1271 return true;
1274 //----------------------------------------------------------------------------
1275 bool cmFileCopier::CheckValue(std::string const& arg)
1277 switch(this->Doing)
1279 case DoingFiles:
1280 if(arg.empty() || cmSystemTools::FileIsFullPath(arg.c_str()))
1282 this->Files.push_back(arg);
1284 else
1286 std::string file = this->Makefile->GetCurrentDirectory();
1287 file += "/" + arg;
1288 this->Files.push_back(file);
1290 break;
1291 case DoingDestination:
1292 if(arg.empty() || cmSystemTools::FileIsFullPath(arg.c_str()))
1294 this->Destination = arg;
1296 else
1298 this->Destination = this->Makefile->GetCurrentOutputDirectory();
1299 this->Destination += "/" + arg;
1301 this->Doing = DoingNone;
1302 break;
1303 case DoingPattern:
1305 // Convert the pattern to a regular expression. Require a
1306 // leading slash and trailing end-of-string in the matched
1307 // string to make sure the pattern matches only whole file
1308 // names.
1309 std::string regex = "/";
1310 regex += cmsys::Glob::PatternToRegex(arg, false);
1311 regex += "$";
1312 this->MatchRules.push_back(MatchRule(regex));
1313 this->CurrentMatchRule = &*(this->MatchRules.end()-1);
1314 if(this->CurrentMatchRule->Regex.is_valid())
1316 this->Doing = DoingNone;
1318 else
1320 cmOStringStream e;
1321 e << "could not compile PATTERN \"" << arg << "\".";
1322 this->FileCommand->SetError(e.str().c_str());
1323 this->Doing = DoingError;
1326 break;
1327 case DoingRegex:
1328 this->MatchRules.push_back(MatchRule(arg));
1329 this->CurrentMatchRule = &*(this->MatchRules.end()-1);
1330 if(this->CurrentMatchRule->Regex.is_valid())
1332 this->Doing = DoingNone;
1334 else
1336 cmOStringStream e;
1337 e << "could not compile REGEX \"" << arg << "\".";
1338 this->FileCommand->SetError(e.str().c_str());
1339 this->Doing = DoingError;
1341 break;
1342 case DoingPermissionsFile:
1343 if(!this->CheckPermissions(arg, this->FilePermissions))
1345 this->Doing = DoingError;
1347 break;
1348 case DoingPermissionsDir:
1349 if(!this->CheckPermissions(arg, this->DirPermissions))
1351 this->Doing = DoingError;
1353 break;
1354 case DoingPermissionsMatch:
1355 if(!this->CheckPermissions(
1356 arg, this->CurrentMatchRule->Properties.Permissions))
1358 this->Doing = DoingError;
1360 break;
1361 default:
1362 return false;
1364 return true;
1367 //----------------------------------------------------------------------------
1368 bool cmFileCopier::Run(std::vector<std::string> const& args)
1370 if(!this->Parse(args))
1372 return false;
1375 std::vector<std::string> const& files = this->Files;
1376 for(std::vector<std::string>::size_type i = 0; i < files.size(); ++i)
1378 // Split the input file into its directory and name components.
1379 std::vector<std::string> fromPathComponents;
1380 cmSystemTools::SplitPath(files[i].c_str(), fromPathComponents);
1381 std::string fromName = *(fromPathComponents.end()-1);
1382 std::string fromDir = cmSystemTools::JoinPath(fromPathComponents.begin(),
1383 fromPathComponents.end()-1);
1385 // Compute the full path to the destination file.
1386 std::string toFile = this->Destination;
1387 std::string const& toName = this->ToName(fromName);
1388 if(!toName.empty())
1390 toFile += "/";
1391 toFile += toName;
1394 // Construct the full path to the source file. The file name may
1395 // have been changed above.
1396 std::string fromFile = fromDir;
1397 if(!fromName.empty())
1399 fromFile += "/";
1400 fromFile += fromName;
1403 if(!this->Install(fromFile.c_str(), toFile.c_str()))
1405 return false;
1408 return true;
1411 //----------------------------------------------------------------------------
1412 bool cmFileCopier::Install(const char* fromFile, const char* toFile)
1414 if(!*fromFile)
1416 cmOStringStream e;
1417 e << "INSTALL encountered an empty string input file name.";
1418 this->FileCommand->SetError(e.str().c_str());
1419 return false;
1422 // Collect any properties matching this file name.
1423 MatchProperties match_properties = this->CollectMatchProperties(fromFile);
1425 // Skip the file if it is excluded.
1426 if(match_properties.Exclude)
1428 return true;
1431 if(cmSystemTools::SameFile(fromFile, toFile))
1433 return true;
1435 else if(cmSystemTools::FileIsSymlink(fromFile))
1437 return this->InstallSymlink(fromFile, toFile);
1439 else if(cmSystemTools::FileIsDirectory(fromFile))
1441 return this->InstallDirectory(fromFile, toFile, match_properties);
1443 else if(cmSystemTools::FileExists(fromFile))
1445 return this->InstallFile(fromFile, toFile, match_properties);
1447 return this->ReportMissing(fromFile);
1450 //----------------------------------------------------------------------------
1451 bool cmFileCopier::InstallSymlink(const char* fromFile, const char* toFile)
1453 // Read the original symlink.
1454 std::string symlinkTarget;
1455 if(!cmSystemTools::ReadSymlink(fromFile, symlinkTarget))
1457 cmOStringStream e;
1458 e << this->Name << " cannot read symlink \"" << fromFile
1459 << "\" to duplicate at \"" << toFile << "\".";
1460 this->FileCommand->SetError(e.str().c_str());
1461 return false;
1464 // Compare the symlink value to that at the destination if not
1465 // always installing.
1466 bool copy = true;
1467 if(!this->Always)
1469 std::string oldSymlinkTarget;
1470 if(cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget))
1472 if(symlinkTarget == oldSymlinkTarget)
1474 copy = false;
1479 // Inform the user about this file installation.
1480 this->ReportCopy(toFile, TypeLink, copy);
1482 if(copy)
1484 // Remove the destination file so we can always create the symlink.
1485 cmSystemTools::RemoveFile(toFile);
1487 // Create the symlink.
1488 if(!cmSystemTools::CreateSymlink(symlinkTarget.c_str(), toFile))
1490 cmOStringStream e;
1491 e << this->Name << " cannot duplicate symlink \"" << fromFile
1492 << "\" at \"" << toFile << "\".";
1493 this->FileCommand->SetError(e.str().c_str());
1494 return false;
1498 return true;
1501 //----------------------------------------------------------------------------
1502 bool cmFileCopier::InstallFile(const char* fromFile, const char* toFile,
1503 MatchProperties const& match_properties)
1505 // Determine whether we will copy the file.
1506 bool copy = true;
1507 if(!this->Always)
1509 // If both files exist with the same time do not copy.
1510 if(!this->FileTimes.FileTimesDiffer(fromFile, toFile))
1512 copy = false;
1516 // Inform the user about this file installation.
1517 this->ReportCopy(toFile, TypeFile, copy);
1519 // Copy the file.
1520 if(copy && !cmSystemTools::CopyAFile(fromFile, toFile, true, false))
1522 cmOStringStream e;
1523 e << this->Name << " cannot copy file \"" << fromFile
1524 << "\" to \"" << toFile << "\".";
1525 this->FileCommand->SetError(e.str().c_str());
1526 return false;
1529 // Set the file modification time of the destination file.
1530 if(copy && !this->Always)
1532 if (!cmSystemTools::CopyFileTime(fromFile, toFile))
1534 cmOStringStream e;
1535 e << this->Name << " cannot set modification time on \""
1536 << toFile << "\"";
1537 this->FileCommand->SetError(e.str().c_str());
1538 return false;
1542 // Set permissions of the destination file.
1543 mode_t permissions = (match_properties.Permissions?
1544 match_properties.Permissions : this->FilePermissions);
1545 if(!permissions)
1547 // No permissions were explicitly provided but the user requested
1548 // that the source file permissions be used.
1549 cmSystemTools::GetPermissions(fromFile, permissions);
1551 return this->SetPermissions(toFile, permissions);
1554 //----------------------------------------------------------------------------
1555 bool cmFileCopier::InstallDirectory(const char* source,
1556 const char* destination,
1557 MatchProperties const& match_properties)
1559 // Inform the user about this directory installation.
1560 this->ReportCopy(destination, TypeDir, true);
1562 // Make sure the destination directory exists.
1563 if(!cmSystemTools::MakeDirectory(destination))
1565 cmOStringStream e;
1566 e << this->Name << " cannot make directory \"" << destination << "\": "
1567 << cmSystemTools::GetLastSystemError();
1568 this->FileCommand->SetError(e.str().c_str());
1569 return false;
1572 // Compute the requested permissions for the destination directory.
1573 mode_t permissions = (match_properties.Permissions?
1574 match_properties.Permissions : this->DirPermissions);
1575 if(!permissions)
1577 // No permissions were explicitly provided but the user requested
1578 // that the source directory permissions be used.
1579 cmSystemTools::GetPermissions(source, permissions);
1582 // Compute the set of permissions required on this directory to
1583 // recursively install files and subdirectories safely.
1584 mode_t required_permissions =
1585 mode_owner_read | mode_owner_write | mode_owner_execute;
1587 // If the required permissions are specified it is safe to set the
1588 // final permissions now. Otherwise we must add the required
1589 // permissions temporarily during file installation.
1590 mode_t permissions_before = 0;
1591 mode_t permissions_after = 0;
1592 if((permissions & required_permissions) == required_permissions)
1594 permissions_before = permissions;
1596 else
1598 permissions_before = permissions | required_permissions;
1599 permissions_after = permissions;
1602 // Set the required permissions of the destination directory.
1603 if(!this->SetPermissions(destination, permissions_before))
1605 return false;
1608 // Load the directory contents to traverse it recursively.
1609 cmsys::Directory dir;
1610 if(source && *source)
1612 dir.Load(source);
1614 unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
1615 for(unsigned long fileNum = 0; fileNum < numFiles; ++fileNum)
1617 if(!(strcmp(dir.GetFile(fileNum), ".") == 0 ||
1618 strcmp(dir.GetFile(fileNum), "..") == 0))
1620 cmsys_stl::string fromPath = source;
1621 fromPath += "/";
1622 fromPath += dir.GetFile(fileNum);
1623 std::string toPath = destination;
1624 toPath += "/";
1625 toPath += dir.GetFile(fileNum);
1626 if(!this->Install(fromPath.c_str(), toPath.c_str()))
1628 return false;
1633 // Set the requested permissions of the destination directory.
1634 return this->SetPermissions(destination, permissions_after);
1637 //----------------------------------------------------------------------------
1638 bool cmFileCommand::HandleCopyCommand(std::vector<std::string> const& args)
1640 cmFileCopier copier(this);
1641 return copier.Run(args);
1644 //----------------------------------------------------------------------------
1645 struct cmFileInstaller: public cmFileCopier
1647 cmFileInstaller(cmFileCommand* command):
1648 cmFileCopier(command, "INSTALL"),
1649 InstallType(cmTarget::INSTALL_FILES),
1650 Optional(false),
1651 DestDirLength(0)
1653 // Installation does not use source permissions by default.
1654 this->UseSourcePermissions = false;
1655 // Check whether to copy files always or only if they have changed.
1656 this->Always =
1657 cmSystemTools::IsOn(cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS"));
1658 // Get the current manifest.
1659 this->Manifest =
1660 this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
1662 ~cmFileInstaller()
1664 // Save the updated install manifest.
1665 this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
1666 this->Manifest.c_str());
1669 protected:
1670 cmTarget::TargetType InstallType;
1671 bool Optional;
1672 int DestDirLength;
1673 std::string Rename;
1675 std::string Manifest;
1676 void ManifestAppend(std::string const& file)
1678 this->Manifest += ";";
1679 this->Manifest += file.substr(this->DestDirLength);
1682 virtual std::string const& ToName(std::string const& fromName)
1683 { return this->Rename.empty()? fromName : this->Rename; }
1685 virtual void ReportCopy(const char* toFile, Type type, bool copy)
1687 std::string message = (copy? "Installing: " : "Up-to-date: ");
1688 message += toFile;
1689 this->Makefile->DisplayStatus(message.c_str(), -1);
1690 if(type != TypeDir)
1692 // Add the file to the manifest.
1693 this->ManifestAppend(toFile);
1696 virtual bool ReportMissing(const char* fromFile)
1698 return (this->Optional ||
1699 this->cmFileCopier::ReportMissing(fromFile));
1701 virtual bool Install(const char* fromFile, const char* toFile)
1703 // Support installing from empty source to make a directory.
1704 if(this->InstallType == cmTarget::INSTALL_DIRECTORY && !*fromFile)
1706 return this->InstallDirectory(fromFile, toFile, MatchProperties());
1708 return this->cmFileCopier::Install(fromFile, toFile);
1711 virtual bool Parse(std::vector<std::string> const& args);
1712 enum
1714 DoingType = DoingLast1,
1715 DoingRename,
1716 DoingSelf24
1718 virtual bool CheckKeyword(std::string const& arg);
1719 virtual bool CheckValue(std::string const& arg);
1720 virtual void DefaultFilePermissions()
1722 this->cmFileCopier::DefaultFilePermissions();
1723 // Add execute permissions based on the target type.
1724 switch(this->InstallType)
1726 case cmTarget::SHARED_LIBRARY:
1727 case cmTarget::MODULE_LIBRARY:
1728 if(this->Makefile->IsOn("CMAKE_INSTALL_SO_NO_EXE"))
1730 break;
1732 case cmTarget::EXECUTABLE:
1733 case cmTarget::INSTALL_PROGRAMS:
1734 this->FilePermissions |= mode_owner_execute;
1735 this->FilePermissions |= mode_group_execute;
1736 this->FilePermissions |= mode_world_execute;
1737 break;
1738 default: break;
1741 bool GetTargetTypeFromString(const std::string& stype);
1742 bool HandleInstallDestination();
1745 //----------------------------------------------------------------------------
1746 bool cmFileInstaller::Parse(std::vector<std::string> const& args)
1748 if(!this->cmFileCopier::Parse(args))
1750 return false;
1753 if(!this->Rename.empty())
1755 if(this->InstallType != cmTarget::INSTALL_FILES &&
1756 this->InstallType != cmTarget::INSTALL_PROGRAMS)
1758 this->FileCommand->SetError("INSTALL option RENAME may be used "
1759 "only with FILES or PROGRAMS.");
1760 return false;
1762 if(this->Files.size() > 1)
1764 this->FileCommand->SetError("INSTALL option RENAME may be used "
1765 "only with one file.");
1766 return false;
1770 if(!this->HandleInstallDestination())
1772 return false;
1775 return true;
1778 //----------------------------------------------------------------------------
1779 bool cmFileInstaller::CheckKeyword(std::string const& arg)
1781 if(arg == "TYPE")
1783 if(this->CurrentMatchRule)
1785 this->NotAfterMatch(arg);
1787 else
1789 this->Doing = DoingType;
1792 else if(arg == "FILES")
1794 if(this->CurrentMatchRule)
1796 this->NotAfterMatch(arg);
1798 else
1800 this->Doing = DoingFiles;
1803 else if(arg == "RENAME")
1805 if(this->CurrentMatchRule)
1807 this->NotAfterMatch(arg);
1809 else
1811 this->Doing = DoingRename;
1814 else if(arg == "OPTIONAL")
1816 if(this->CurrentMatchRule)
1818 this->NotAfterMatch(arg);
1820 else
1822 this->Doing = DoingNone;
1823 this->Optional = true;
1826 else if(arg == "PERMISSIONS")
1828 if(this->CurrentMatchRule)
1830 this->Doing = DoingPermissionsMatch;
1832 else
1834 // file(INSTALL) aliases PERMISSIONS to FILE_PERMISSIONS
1835 this->Doing = DoingPermissionsFile;
1836 this->UseGivenPermissionsFile = true;
1839 else if(arg == "DIR_PERMISSIONS")
1841 if(this->CurrentMatchRule)
1843 this->NotAfterMatch(arg);
1845 else
1847 // file(INSTALL) aliases DIR_PERMISSIONS to DIRECTORY_PERMISSIONS
1848 this->Doing = DoingPermissionsDir;
1849 this->UseGivenPermissionsDir = true;
1852 else if(arg == "COMPONENTS" || arg == "CONFIGURATIONS" ||
1853 arg == "PROPERTIES")
1855 if(this->Makefile->IsOn("CMAKE_INSTALL_SELF_2_4"))
1857 // When CMake 2.4 builds this CMake version we need to support
1858 // the install scripts it generates since it asks this CMake
1859 // to install itself using the rules it generated.
1860 this->Doing = DoingSelf24;
1862 else
1864 cmOStringStream e;
1865 e << "INSTALL called with old-style " << arg << " argument. "
1866 << "This script was generated with an older version of CMake. "
1867 << "Re-run this cmake version on your build tree.";
1868 this->FileCommand->SetError(e.str().c_str());
1869 this->Doing = DoingError;
1872 else
1874 return this->cmFileCopier::CheckKeyword(arg);
1876 return true;
1879 //----------------------------------------------------------------------------
1880 bool cmFileInstaller::CheckValue(std::string const& arg)
1882 switch(this->Doing)
1884 case DoingType:
1885 if(!this->GetTargetTypeFromString(arg))
1887 this->Doing = DoingError;
1889 break;
1890 case DoingRename:
1891 this->Rename = arg;
1892 break;
1893 case DoingSelf24:
1894 // Ignore these arguments for compatibility. This should be
1895 // reached only when CMake 2.4 is installing the current
1896 // CMake. It can be removed when CMake 2.6 or higher is
1897 // required to build CMake.
1898 break;
1899 default:
1900 return this->cmFileCopier::CheckValue(arg);
1902 return true;
1905 //----------------------------------------------------------------------------
1906 bool cmFileInstaller
1907 ::GetTargetTypeFromString(const std::string& stype)
1909 if ( stype == "EXECUTABLE" )
1911 this->InstallType = cmTarget::EXECUTABLE;
1913 else if ( stype == "FILE" )
1915 this->InstallType = cmTarget::INSTALL_FILES;
1917 else if ( stype == "PROGRAM" )
1919 this->InstallType = cmTarget::INSTALL_PROGRAMS;
1921 else if ( stype == "STATIC_LIBRARY" )
1923 this->InstallType = cmTarget::STATIC_LIBRARY;
1925 else if ( stype == "SHARED_LIBRARY" )
1927 this->InstallType = cmTarget::SHARED_LIBRARY;
1929 else if ( stype == "MODULE" )
1931 this->InstallType = cmTarget::MODULE_LIBRARY;
1933 else if ( stype == "DIRECTORY" )
1935 this->InstallType = cmTarget::INSTALL_DIRECTORY;
1937 else
1939 cmOStringStream e;
1940 e << "Option TYPE given uknown value \"" << stype << "\".";
1941 this->FileCommand->SetError(e.str().c_str());
1942 return false;
1944 return true;
1947 //----------------------------------------------------------------------------
1948 bool cmFileInstaller::HandleInstallDestination()
1950 std::string& destination = this->Destination;
1952 // allow for / to be a valid destination
1953 if ( destination.size() < 2 && destination != "/" )
1955 this->FileCommand->SetError("called with inapropriate arguments. "
1956 "No DESTINATION provided or .");
1957 return false;
1960 const char* destdir = cmSystemTools::GetEnv("DESTDIR");
1961 if ( destdir && *destdir )
1963 std::string sdestdir = destdir;
1964 cmSystemTools::ConvertToUnixSlashes(sdestdir);
1965 char ch1 = destination[0];
1966 char ch2 = destination[1];
1967 char ch3 = 0;
1968 if ( destination.size() > 2 )
1970 ch3 = destination[2];
1972 int skip = 0;
1973 if ( ch1 != '/' )
1975 int relative = 0;
1976 if (((ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z')) &&
1977 ch2 == ':' )
1979 // Assume windows
1980 // let's do some destdir magic:
1981 skip = 2;
1982 if ( ch3 != '/' )
1984 relative = 1;
1987 else
1989 relative = 1;
1991 if ( relative )
1993 // This is relative path on unix or windows. Since we are doing
1994 // destdir, this case does not make sense.
1995 this->FileCommand->SetError(
1996 "called with relative DESTINATION. This "
1997 "does not make sense when using DESTDIR. Specify "
1998 "absolute path or remove DESTDIR environment variable.");
1999 return false;
2002 else
2004 if ( ch2 == '/' )
2006 // looks like a network path.
2007 std::string message = "called with network path DESTINATION. This "
2008 "does not make sense when using DESTDIR. Specify local "
2009 "absolute path or remove DESTDIR environment variable."
2010 "\nDESTINATION=\n";
2011 message += destination;
2012 this->FileCommand->SetError(message.c_str());
2013 return false;
2016 destination = sdestdir + (destination.c_str() + skip);
2017 this->DestDirLength = int(sdestdir.size());
2020 if ( !cmSystemTools::FileExists(destination.c_str()) )
2022 if ( !cmSystemTools::MakeDirectory(destination.c_str()) )
2024 std::string errstring = "cannot create directory: " + destination +
2025 ". Maybe need administrative privileges.";
2026 this->FileCommand->SetError(errstring.c_str());
2027 return false;
2030 if ( !cmSystemTools::FileIsDirectory(destination.c_str()) )
2032 std::string errstring = "INSTALL destination: " + destination +
2033 " is not a directory.";
2034 this->FileCommand->SetError(errstring.c_str());
2035 return false;
2037 return true;
2040 //----------------------------------------------------------------------------
2041 bool
2042 cmFileCommand::HandleRPathChangeCommand(std::vector<std::string> const& args)
2044 // Evaluate arguments.
2045 const char* file = 0;
2046 const char* oldRPath = 0;
2047 const char* newRPath = 0;
2048 enum Doing { DoingNone, DoingFile, DoingOld, DoingNew };
2049 Doing doing = DoingNone;
2050 for(unsigned int i=1; i < args.size(); ++i)
2052 if(args[i] == "OLD_RPATH")
2054 doing = DoingOld;
2056 else if(args[i] == "NEW_RPATH")
2058 doing = DoingNew;
2060 else if(args[i] == "FILE")
2062 doing = DoingFile;
2064 else if(doing == DoingFile)
2066 file = args[i].c_str();
2067 doing = DoingNone;
2069 else if(doing == DoingOld)
2071 oldRPath = args[i].c_str();
2072 doing = DoingNone;
2074 else if(doing == DoingNew)
2076 newRPath = args[i].c_str();
2077 doing = DoingNone;
2079 else
2081 cmOStringStream e;
2082 e << "RPATH_CHANGE given unknown argument " << args[i];
2083 this->SetError(e.str().c_str());
2084 return false;
2087 if(!file)
2089 this->SetError("RPATH_CHANGE not given FILE option.");
2090 return false;
2092 if(!oldRPath)
2094 this->SetError("RPATH_CHANGE not given OLD_RPATH option.");
2095 return false;
2097 if(!newRPath)
2099 this->SetError("RPATH_CHANGE not given NEW_RPATH option.");
2100 return false;
2102 if(!cmSystemTools::FileExists(file, true))
2104 cmOStringStream e;
2105 e << "RPATH_CHANGE given FILE \"" << file << "\" that does not exist.";
2106 this->SetError(e.str().c_str());
2107 return false;
2109 bool success = true;
2110 cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
2111 bool have_ft = cmSystemTools::FileTimeGet(file, ft);
2112 std::string emsg;
2113 bool changed;
2114 if(!cmSystemTools::ChangeRPath(file, oldRPath, newRPath, &emsg, &changed))
2116 cmOStringStream e;
2117 e << "RPATH_CHANGE could not write new RPATH:\n"
2118 << " " << newRPath << "\n"
2119 << "to the file:\n"
2120 << " " << file << "\n"
2121 << emsg;
2122 this->SetError(e.str().c_str());
2123 success = false;
2125 if(success)
2127 if(changed)
2129 std::string message = "Set runtime path of \"";
2130 message += file;
2131 message += "\" to \"";
2132 message += newRPath;
2133 message += "\"";
2134 this->Makefile->DisplayStatus(message.c_str(), -1);
2136 if(have_ft)
2138 cmSystemTools::FileTimeSet(file, ft);
2141 cmSystemTools::FileTimeDelete(ft);
2142 return success;
2145 //----------------------------------------------------------------------------
2146 bool
2147 cmFileCommand::HandleRPathRemoveCommand(std::vector<std::string> const& args)
2149 // Evaluate arguments.
2150 const char* file = 0;
2151 enum Doing { DoingNone, DoingFile };
2152 Doing doing = DoingNone;
2153 for(unsigned int i=1; i < args.size(); ++i)
2155 if(args[i] == "FILE")
2157 doing = DoingFile;
2159 else if(doing == DoingFile)
2161 file = args[i].c_str();
2162 doing = DoingNone;
2164 else
2166 cmOStringStream e;
2167 e << "RPATH_REMOVE given unknown argument " << args[i];
2168 this->SetError(e.str().c_str());
2169 return false;
2172 if(!file)
2174 this->SetError("RPATH_REMOVE not given FILE option.");
2175 return false;
2177 if(!cmSystemTools::FileExists(file, true))
2179 cmOStringStream e;
2180 e << "RPATH_REMOVE given FILE \"" << file << "\" that does not exist.";
2181 this->SetError(e.str().c_str());
2182 return false;
2184 bool success = true;
2185 cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
2186 bool have_ft = cmSystemTools::FileTimeGet(file, ft);
2187 std::string emsg;
2188 bool removed;
2189 if(!cmSystemTools::RemoveRPath(file, &emsg, &removed))
2191 cmOStringStream e;
2192 e << "RPATH_REMOVE could not remove RPATH from file:\n"
2193 << " " << file << "\n"
2194 << emsg;
2195 this->SetError(e.str().c_str());
2196 success = false;
2198 if(success)
2200 if(removed)
2202 std::string message = "Removed runtime path from \"";
2203 message += file;
2204 message += "\"";
2205 this->Makefile->DisplayStatus(message.c_str(), -1);
2207 if(have_ft)
2209 cmSystemTools::FileTimeSet(file, ft);
2212 cmSystemTools::FileTimeDelete(ft);
2213 return success;
2216 //----------------------------------------------------------------------------
2217 bool
2218 cmFileCommand::HandleRPathCheckCommand(std::vector<std::string> const& args)
2220 // Evaluate arguments.
2221 const char* file = 0;
2222 const char* rpath = 0;
2223 enum Doing { DoingNone, DoingFile, DoingRPath };
2224 Doing doing = DoingNone;
2225 for(unsigned int i=1; i < args.size(); ++i)
2227 if(args[i] == "RPATH")
2229 doing = DoingRPath;
2231 else if(args[i] == "FILE")
2233 doing = DoingFile;
2235 else if(doing == DoingFile)
2237 file = args[i].c_str();
2238 doing = DoingNone;
2240 else if(doing == DoingRPath)
2242 rpath = args[i].c_str();
2243 doing = DoingNone;
2245 else
2247 cmOStringStream e;
2248 e << "RPATH_CHECK given unknown argument " << args[i];
2249 this->SetError(e.str().c_str());
2250 return false;
2253 if(!file)
2255 this->SetError("RPATH_CHECK not given FILE option.");
2256 return false;
2258 if(!rpath)
2260 this->SetError("RPATH_CHECK not given RPATH option.");
2261 return false;
2264 // If the file exists but does not have the desired RPath then
2265 // delete it. This is used during installation to re-install a file
2266 // if its RPath will change.
2267 if(cmSystemTools::FileExists(file, true) &&
2268 !cmSystemTools::CheckRPath(file, rpath))
2270 cmSystemTools::RemoveFile(file);
2273 return true;
2276 //----------------------------------------------------------------------------
2277 bool cmFileCommand::HandleInstallCommand(std::vector<std::string> const& args)
2279 cmFileInstaller installer(this);
2280 return installer.Run(args);
2283 //----------------------------------------------------------------------------
2284 bool cmFileCommand::HandleRelativePathCommand(
2285 std::vector<std::string> const& args)
2287 if(args.size() != 4 )
2289 this->SetError("called with incorrect number of arguments");
2290 return false;
2293 const std::string& outVar = args[1];
2294 const std::string& directoryName = args[2];
2295 const std::string& fileName = args[3];
2297 if(!cmSystemTools::FileIsFullPath(directoryName.c_str()))
2299 std::string errstring =
2300 "RelativePath must be passed a full path to the directory: "
2301 + directoryName;
2302 this->SetError(errstring.c_str());
2303 return false;
2305 if(!cmSystemTools::FileIsFullPath(fileName.c_str()))
2307 std::string errstring =
2308 "RelativePath must be passed a full path to the file: "
2309 + fileName;
2310 this->SetError(errstring.c_str());
2311 return false;
2314 std::string res = cmSystemTools::RelativePath(directoryName.c_str(),
2315 fileName.c_str());
2316 this->Makefile->AddDefinition(outVar.c_str(),
2317 res.c_str());
2318 return true;
2322 //----------------------------------------------------------------------------
2323 bool cmFileCommand::HandleRename(std::vector<std::string> const& args)
2325 if(args.size() != 3)
2327 this->SetError("given incorrect number of arguments.");
2328 return false;
2331 // Compute full path for old and new names.
2332 std::string oldname = args[1];
2333 if(!cmsys::SystemTools::FileIsFullPath(oldname.c_str()))
2335 oldname = this->Makefile->GetCurrentDirectory();
2336 oldname += "/" + args[1];
2338 std::string newname = args[2];
2339 if(!cmsys::SystemTools::FileIsFullPath(newname.c_str()))
2341 newname = this->Makefile->GetCurrentDirectory();
2342 newname += "/" + args[2];
2345 if(!cmSystemTools::RenameFile(oldname.c_str(), newname.c_str()))
2347 std::string err = cmSystemTools::GetLastSystemError();
2348 cmOStringStream e;
2349 e << "RENAME failed to rename\n"
2350 << " " << oldname << "\n"
2351 << "to\n"
2352 << " " << newname << "\n"
2353 << "because: " << err << "\n";
2354 this->SetError(e.str().c_str());
2355 return false;
2357 return true;
2361 //----------------------------------------------------------------------------
2362 bool cmFileCommand::HandleRemove(std::vector<std::string> const& args,
2363 bool recurse)
2366 std::string message;
2367 std::vector<std::string>::const_iterator i = args.begin();
2369 i++; // Get rid of subcommand
2370 for(;i != args.end(); ++i)
2372 std::string fileName = *i;
2373 if(!cmsys::SystemTools::FileIsFullPath(fileName.c_str()))
2375 fileName = this->Makefile->GetCurrentDirectory();
2376 fileName += "/" + *i;
2379 if(cmSystemTools::FileIsDirectory(fileName.c_str()) && recurse)
2381 cmSystemTools::RemoveADirectory(fileName.c_str());
2383 else
2385 cmSystemTools::RemoveFile(fileName.c_str());
2388 return true;
2391 //----------------------------------------------------------------------------
2392 bool cmFileCommand::HandleCMakePathCommand(std::vector<std::string>
2393 const& args,
2394 bool nativePath)
2396 std::vector<std::string>::const_iterator i = args.begin();
2397 if(args.size() != 3)
2399 this->SetError("FILE(SYSTEM_PATH ENV result) must be called with "
2400 "only three arguments.");
2401 return false;
2403 i++; // Get rid of subcommand
2404 #if defined(_WIN32) && !defined(__CYGWIN__)
2405 char pathSep = ';';
2406 #else
2407 char pathSep = ':';
2408 #endif
2409 std::vector<cmsys::String> path = cmSystemTools::SplitString(i->c_str(),
2410 pathSep);
2411 i++;
2412 const char* var = i->c_str();
2413 std::string value;
2414 for(std::vector<cmsys::String>::iterator j = path.begin();
2415 j != path.end(); ++j)
2417 if(j != path.begin())
2419 value += ";";
2421 if(!nativePath)
2423 cmSystemTools::ConvertToUnixSlashes(*j);
2425 else
2427 *j = cmSystemTools::ConvertToOutputPath(j->c_str());
2428 // remove double quotes in the path
2429 cmsys::String& s = *j;
2431 if(s.size() > 1 && s[0] == '\"' && s[s.size()-1] == '\"')
2433 s = s.substr(1,s.size()-2);
2436 value += *j;
2438 this->Makefile->AddDefinition(var, value.c_str());
2439 return true;
2441 #if defined(CMAKE_BUILD_WITH_CMAKE)
2443 // Stuff for curl download
2444 typedef std::vector<char> cmFileCommandVectorOfChar;
2445 namespace{
2446 size_t
2447 cmFileCommandWriteMemoryCallback(void *ptr, size_t size, size_t nmemb,
2448 void *data)
2450 register int realsize = (int)(size * nmemb);
2451 std::ofstream* fout = static_cast<std::ofstream*>(data);
2452 const char* chPtr = static_cast<char*>(ptr);
2453 fout->write(chPtr, realsize);
2454 return realsize;
2457 static size_t
2458 cmFileCommandCurlDebugCallback(CURL *, curl_infotype, char *chPtr,
2459 size_t size, void *data)
2461 cmFileCommandVectorOfChar *vec
2462 = static_cast<cmFileCommandVectorOfChar*>(data);
2463 vec->insert(vec->end(), chPtr, chPtr + size);
2465 return size;
2471 #endif
2473 bool
2474 cmFileCommand::HandleDownloadCommand(std::vector<std::string>
2475 const& args)
2477 #if defined(CMAKE_BUILD_WITH_CMAKE)
2478 std::vector<std::string>::const_iterator i = args.begin();
2479 if(args.size() < 3)
2481 this->SetError("FILE(DOWNLOAD url file) must be called with "
2482 "at least three arguments.");
2483 return false;
2485 i++; // Get rid of subcommand
2486 std::string url = *i;
2487 i++;
2488 std::string file = *i;
2489 i++;
2490 double timeout = 0;
2491 std::string verboseLog;
2492 std::string statusVar;
2493 while(i != args.end())
2495 if(*i == "TIMEOUT")
2497 i++;
2498 if(i != args.end())
2500 timeout = atof(i->c_str());
2502 else
2504 this->SetError("FILE(DOWNLOAD url file TIMEOUT time) missing "
2505 "time for TIMEOUT.");
2506 return false;
2509 else if(*i == "LOG")
2511 i++;
2512 if( i == args.end())
2514 this->SetError("FILE(DOWNLOAD url file LOG VAR) missing "
2515 "VAR for LOG.");
2516 return false;
2518 verboseLog = *i;
2520 else if(*i == "STATUS")
2522 i++;
2523 if( i == args.end())
2525 this->SetError("FILE(DOWNLOAD url file STATUS VAR) missing "
2526 "VAR for STATUS.");
2527 return false;
2529 statusVar = *i;
2531 i++;
2534 std::string dir = cmSystemTools::GetFilenamePath(file.c_str());
2535 if(!cmSystemTools::FileExists(dir.c_str()) &&
2536 !cmSystemTools::MakeDirectory(dir.c_str()))
2538 std::string errstring = "FILE(DOWNLOAD ) error; cannot create directory: "
2539 + dir + ". Maybe need administrative privileges.";
2540 this->SetError(errstring.c_str());
2541 return false;
2544 std::ofstream fout(file.c_str(), std::ios::binary);
2545 if(!fout)
2547 this->SetError("FILE(DOWNLOAD url file TIMEOUT time) can not open "
2548 "file for write.");
2549 return false;
2551 CURL *curl;
2552 curl_global_init(CURL_GLOBAL_DEFAULT);
2553 curl = curl_easy_init();
2554 if(!curl)
2556 this->SetError("FILE(DOWNLOAD ) error "
2557 "initializing curl.");
2558 return false;
2561 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
2562 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
2563 cmFileCommandWriteMemoryCallback);
2564 curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
2565 cmFileCommandCurlDebugCallback);
2566 cmFileCommandVectorOfChar chunkDebug;
2567 ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&fout);
2568 ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
2569 if(verboseLog.size())
2571 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
2573 if(timeout > 0)
2575 curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout );
2577 CURLcode res = curl_easy_perform(curl);
2578 /* always cleanup */
2579 curl_easy_cleanup(curl);
2580 if(statusVar.size())
2582 cmOStringStream result;
2583 result << (int)res << ";\"" << curl_easy_strerror(res) << "\"";
2584 this->Makefile->AddDefinition(statusVar.c_str(),
2585 result.str().c_str());
2587 curl_global_cleanup();
2588 if(chunkDebug.size())
2590 chunkDebug.push_back(0);
2591 if(CURLE_OPERATION_TIMEOUTED == res)
2593 std::string output = &*chunkDebug.begin();
2595 if(verboseLog.size())
2597 this->Makefile->AddDefinition(verboseLog.c_str(),
2598 &*chunkDebug.begin());
2602 this->Makefile->AddDefinition(verboseLog.c_str(),
2603 &*chunkDebug.begin());
2605 return true;
2606 #else
2607 this->SetError("FILE(DOWNLOAD ) "
2608 "not supported in bootstrap cmake ");
2609 return false;
2610 #endif