ENH: fix uppercase version so defines are not upper as well
[cmake.git] / Source / cmFileCommand.cxx
blobf72eb4a06d517dc265ed58cca5498a3d696cff79
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmFileCommand.cxx,v $
5 Language: C++
6 Date: $Date: 2008-09-11 18:34:04 $
7 Version: $Revision: 1.113 $
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 == "RPATH_CHANGE" || subCommand == "CHRPATH" )
117 return this->HandleRPathChangeCommand(args);
119 else if ( subCommand == "RPATH_CHECK" )
121 return this->HandleRPathCheckCommand(args);
123 else if ( subCommand == "RPATH_REMOVE" )
125 return this->HandleRPathRemoveCommand(args);
127 else if ( subCommand == "RELATIVE_PATH" )
129 return this->HandleRelativePathCommand(args);
131 else if ( subCommand == "TO_CMAKE_PATH" )
133 return this->HandleCMakePathCommand(args, false);
135 else if ( subCommand == "TO_NATIVE_PATH" )
137 return this->HandleCMakePathCommand(args, true);
140 std::string e = "does not recognize sub-command "+subCommand;
141 this->SetError(e.c_str());
142 return false;
145 //----------------------------------------------------------------------------
146 bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args,
147 bool append)
149 std::string message;
150 std::vector<std::string>::const_iterator i = args.begin();
152 i++; // Get rid of subcommand
154 std::string fileName = *i;
155 if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
157 fileName = this->Makefile->GetCurrentDirectory();
158 fileName += "/" + *i;
161 i++;
163 for(;i != args.end(); ++i)
165 message += *i;
167 if ( !this->Makefile->CanIWriteThisFile(fileName.c_str()) )
169 std::string e
170 = "attempted to write a file: " + fileName +
171 " into a source directory.";
172 this->SetError(e.c_str());
173 cmSystemTools::SetFatalErrorOccured();
174 return false;
176 std::string dir = cmSystemTools::GetFilenamePath(fileName);
177 cmSystemTools::MakeDirectory(dir.c_str());
179 mode_t mode =
180 #if defined( _MSC_VER ) || defined( __MINGW32__ )
181 S_IREAD | S_IWRITE
182 #elif defined( __BORLANDC__ )
183 S_IRUSR | S_IWUSR
184 #else
185 S_IRUSR | S_IWUSR |
186 S_IRGRP |
187 S_IROTH
188 #endif
191 // Set permissions to writable
192 if ( cmSystemTools::GetPermissions(fileName.c_str(), mode) )
194 cmSystemTools::SetPermissions(fileName.c_str(),
195 #if defined( _MSC_VER ) || defined( __MINGW32__ )
196 S_IREAD | S_IWRITE
197 #else
198 S_IRUSR | S_IWUSR
199 #endif
202 // If GetPermissions fails, pretend like it is ok. File open will fail if
203 // the file is not writable
204 std::ofstream file(fileName.c_str(), append?std::ios::app: std::ios::out);
205 if ( !file )
207 std::string error = "Internal CMake error when trying to open file: ";
208 error += fileName.c_str();
209 error += " for writing.";
210 this->SetError(error.c_str());
211 return false;
213 file << message;
214 file.close();
215 cmSystemTools::SetPermissions(fileName.c_str(), mode);
216 return true;
219 //----------------------------------------------------------------------------
220 bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args)
222 if ( args.size() < 3 )
224 this->SetError("READ must be called with at least two additional "
225 "arguments");
226 return false;
229 cmCommandArgumentsHelper argHelper;
230 cmCommandArgumentGroup group;
232 cmCAString readArg (&argHelper, "READ");
233 cmCAString fileNameArg (&argHelper, 0);
234 cmCAString resultArg (&argHelper, 0);
236 cmCAString offsetArg (&argHelper, "OFFSET", &group);
237 cmCAString limitArg (&argHelper, "LIMIT", &group);
238 cmCAEnabler hexOutputArg (&argHelper, "HEX", &group);
239 readArg.Follows(0);
240 fileNameArg.Follows(&readArg);
241 resultArg.Follows(&fileNameArg);
242 group.Follows(&resultArg);
243 argHelper.Parse(&args, 0);
245 std::string fileName = fileNameArg.GetString();
246 if ( !cmsys::SystemTools::FileIsFullPath(fileName.c_str()) )
248 fileName = this->Makefile->GetCurrentDirectory();
249 fileName += "/" + fileNameArg.GetString();
252 std::string variable = resultArg.GetString();
254 // Open the specified file.
255 #if defined(_WIN32) || defined(__CYGWIN__)
256 std::ifstream file(fileName.c_str(), std::ios::in |
257 (hexOutputArg.IsEnabled() ? std::ios::binary : std::ios::in));
258 #else
259 std::ifstream file(fileName.c_str(), std::ios::in);
260 #endif
262 if ( !file )
264 std::string error = "Internal CMake error when trying to open file: ";
265 error += fileName.c_str();
266 error += " for reading.";
267 this->SetError(error.c_str());
268 return false;
271 // is there a limit?
272 long sizeLimit = -1;
273 if (limitArg.GetString().size() > 0)
275 sizeLimit = atoi(limitArg.GetCString());
278 // is there an offset?
279 long offset = 0;
280 if (offsetArg.GetString().size() > 0)
282 offset = atoi(offsetArg.GetCString());
285 file.seekg(offset);
287 std::string output;
289 if (hexOutputArg.IsEnabled())
291 // Convert part of the file into hex code
292 int c;
293 while((sizeLimit != 0) && (c = file.get(), file))
295 char hex[4];
296 sprintf(hex, "%x", c&0xff);
297 output += hex;
298 if (sizeLimit > 0)
300 sizeLimit--;
304 else
306 std::string line;
307 bool has_newline = false;
308 while (sizeLimit != 0 &&
309 cmSystemTools::GetLineFromStream(file, line, &has_newline,
310 sizeLimit) )
312 if (sizeLimit > 0)
314 sizeLimit = sizeLimit - static_cast<long>(line.size());
315 if (has_newline)
317 sizeLimit--;
319 if (sizeLimit < 0)
321 sizeLimit = 0;
324 output += line;
325 if ( has_newline )
327 output += "\n";
331 this->Makefile->AddDefinition(variable.c_str(), output.c_str());
332 return true;
335 //----------------------------------------------------------------------------
336 bool cmFileCommand::HandleStringsCommand(std::vector<std::string> const& args)
338 if(args.size() < 3)
340 this->SetError("STRINGS requires a file name and output variable");
341 return false;
344 // Get the file to read.
345 std::string fileName = args[1];
346 if(!cmsys::SystemTools::FileIsFullPath(fileName.c_str()))
348 fileName = this->Makefile->GetCurrentDirectory();
349 fileName += "/" + args[1];
352 // Get the variable in which to store the results.
353 std::string outVar = args[2];
355 // Parse the options.
356 enum { arg_none,
357 arg_limit_input,
358 arg_limit_output,
359 arg_limit_count,
360 arg_length_minimum,
361 arg_length_maximum,
362 arg__maximum,
363 arg_regex };
364 unsigned int minlen = 0;
365 unsigned int maxlen = 0;
366 int limit_input = -1;
367 int limit_output = -1;
368 unsigned int limit_count = 0;
369 cmsys::RegularExpression regex;
370 bool have_regex = false;
371 bool newline_consume = false;
372 bool hex_conversion_enabled = true;
373 int arg_mode = arg_none;
374 for(unsigned int i=3; i < args.size(); ++i)
376 if(args[i] == "LIMIT_INPUT")
378 arg_mode = arg_limit_input;
380 else if(args[i] == "LIMIT_OUTPUT")
382 arg_mode = arg_limit_output;
384 else if(args[i] == "LIMIT_COUNT")
386 arg_mode = arg_limit_count;
388 else if(args[i] == "LENGTH_MINIMUM")
390 arg_mode = arg_length_minimum;
392 else if(args[i] == "LENGTH_MAXIMUM")
394 arg_mode = arg_length_maximum;
396 else if(args[i] == "REGEX")
398 arg_mode = arg_regex;
400 else if(args[i] == "NEWLINE_CONSUME")
402 newline_consume = true;
403 arg_mode = arg_none;
405 else if(args[i] == "NO_HEX_CONVERSION")
407 hex_conversion_enabled = false;
408 arg_mode = arg_none;
410 else if(arg_mode == arg_limit_input)
412 if(sscanf(args[i].c_str(), "%d", &limit_input) != 1 ||
413 limit_input < 0)
415 cmOStringStream e;
416 e << "STRINGS option LIMIT_INPUT value \""
417 << args[i] << "\" is not an unsigned integer.";
418 this->SetError(e.str().c_str());
419 return false;
421 arg_mode = arg_none;
423 else if(arg_mode == arg_limit_output)
425 if(sscanf(args[i].c_str(), "%d", &limit_output) != 1 ||
426 limit_output < 0)
428 cmOStringStream e;
429 e << "STRINGS option LIMIT_OUTPUT value \""
430 << args[i] << "\" is not an unsigned integer.";
431 this->SetError(e.str().c_str());
432 return false;
434 arg_mode = arg_none;
436 else if(arg_mode == arg_limit_count)
438 int count;
439 if(sscanf(args[i].c_str(), "%d", &count) != 1 || count < 0)
441 cmOStringStream e;
442 e << "STRINGS option LIMIT_COUNT value \""
443 << args[i] << "\" is not an unsigned integer.";
444 this->SetError(e.str().c_str());
445 return false;
447 limit_count = count;
448 arg_mode = arg_none;
450 else if(arg_mode == arg_length_minimum)
452 int len;
453 if(sscanf(args[i].c_str(), "%d", &len) != 1 || len < 0)
455 cmOStringStream e;
456 e << "STRINGS option LENGTH_MINIMUM value \""
457 << args[i] << "\" is not an unsigned integer.";
458 this->SetError(e.str().c_str());
459 return false;
461 minlen = len;
462 arg_mode = arg_none;
464 else if(arg_mode == arg_length_maximum)
466 int len;
467 if(sscanf(args[i].c_str(), "%d", &len) != 1 || len < 0)
469 cmOStringStream e;
470 e << "STRINGS option LENGTH_MAXIMUM value \""
471 << args[i] << "\" is not an unsigned integer.";
472 this->SetError(e.str().c_str());
473 return false;
475 maxlen = len;
476 arg_mode = arg_none;
478 else if(arg_mode == arg_regex)
480 if(!regex.compile(args[i].c_str()))
482 cmOStringStream e;
483 e << "STRINGS option REGEX value \""
484 << args[i] << "\" could not be compiled.";
485 this->SetError(e.str().c_str());
486 return false;
488 have_regex = true;
489 arg_mode = arg_none;
491 else
493 cmOStringStream e;
494 e << "STRINGS given unknown argument \""
495 << args[i] << "\"";
496 this->SetError(e.str().c_str());
497 return false;
501 if (hex_conversion_enabled)
503 // TODO: should work without temp file, but just on a memory buffer
504 std::string binaryFileName = this->Makefile->GetCurrentOutputDirectory();
505 binaryFileName += cmake::GetCMakeFilesDirectory();
506 binaryFileName += "/FileCommandStringsBinaryFile";
507 if(cmHexFileConverter::TryConvert(fileName.c_str(),binaryFileName.c_str()))
509 fileName = binaryFileName;
513 // Open the specified file.
514 #if defined(_WIN32) || defined(__CYGWIN__)
515 std::ifstream fin(fileName.c_str(), std::ios::in | std::ios::binary);
516 #else
517 std::ifstream fin(fileName.c_str(), std::ios::in);
518 #endif
519 if(!fin)
521 cmOStringStream e;
522 e << "STRINGS file \"" << fileName << "\" cannot be read.";
523 this->SetError(e.str().c_str());
524 return false;
527 // Parse strings out of the file.
528 int output_size = 0;
529 std::vector<std::string> strings;
530 std::string s;
531 int c;
532 while((!limit_count || strings.size() < limit_count) &&
533 (limit_input < 0 || static_cast<int>(fin.tellg()) < limit_input) &&
534 (c = fin.get(), fin))
536 if(c == '\0')
538 // A terminating null character has been found. Check if the
539 // current string matches the requirements. Since it was
540 // terminated by a null character, we require that the length be
541 // at least one no matter what the user specified.
542 if(s.length() >= minlen && s.length() >= 1 &&
543 (!have_regex || regex.find(s.c_str())))
545 output_size += static_cast<int>(s.size()) + 1;
546 if(limit_output >= 0 && output_size >= limit_output)
548 s = "";
549 break;
551 strings.push_back(s);
554 // Reset the string to empty.
555 s = "";
557 else if(c == '\n' && !newline_consume)
559 // The current line has been terminated. Check if the current
560 // string matches the requirements. The length may now be as
561 // low as zero since blank lines are allowed.
562 if(s.length() >= minlen &&
563 (!have_regex || regex.find(s.c_str())))
565 output_size += static_cast<int>(s.size()) + 1;
566 if(limit_output >= 0 && output_size >= limit_output)
568 s = "";
569 break;
571 strings.push_back(s);
574 // Reset the string to empty.
575 s = "";
577 else if(c == '\r')
579 // Ignore CR character to make output always have UNIX newlines.
581 else if(c >= 0x20 && c < 0x7F || c == '\t' || c == '\f' ||
582 (c == '\n' && newline_consume))
584 // This is an ASCII character that may be part of a string.
585 s += c;
587 else
589 // This is a non-string character. Reset the string to emtpy.
590 s = "";
593 // Terminate a string if the maximum length is reached.
594 if(maxlen > 0 && s.size() == maxlen)
596 if(s.length() >= minlen &&
597 (!have_regex || regex.find(s.c_str())))
599 output_size += static_cast<int>(s.size()) + 1;
600 if(limit_output >= 0 && output_size >= limit_output)
602 s = "";
603 break;
605 strings.push_back(s);
607 s = "";
611 // If there is a non-empty current string we have hit the end of the
612 // input file or the input size limit. Check if the current string
613 // matches the requirements.
614 if((!limit_count || strings.size() < limit_count) &&
615 !s.empty() && s.length() >= minlen &&
616 (!have_regex || regex.find(s.c_str())))
618 output_size += static_cast<int>(s.size()) + 1;
619 if(limit_output < 0 || output_size < limit_output)
621 strings.push_back(s);
625 // Encode the result in a CMake list.
626 const char* sep = "";
627 std::string output;
628 for(std::vector<std::string>::const_iterator si = strings.begin();
629 si != strings.end(); ++si)
631 // Separate the strings in the output to make it a list.
632 output += sep;
633 sep = ";";
635 // Store the string in the output, but escape semicolons to
636 // make sure it is a list.
637 std::string const& sr = *si;
638 for(unsigned int i=0; i < sr.size(); ++i)
640 if(sr[i] == ';')
642 output += '\\';
644 output += sr[i];
648 // Save the output in a makefile variable.
649 this->Makefile->AddDefinition(outVar.c_str(), output.c_str());
650 return true;
653 //----------------------------------------------------------------------------
654 bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
655 bool recurse)
657 if ( args.size() < 2 )
659 this->SetError("GLOB requires at least a variable name");
660 return false;
663 std::vector<std::string>::const_iterator i = args.begin();
665 i++; // Get rid of subcommand
667 std::string variable = *i;
668 i++;
669 cmsys::Glob g;
670 g.SetRecurse(recurse);
672 bool explicitFollowSymlinks = false;
673 cmPolicies::PolicyStatus status =
674 this->Makefile->GetPolicyStatus(cmPolicies::CMP0009);
675 if(recurse)
677 switch(status)
679 case cmPolicies::NEW:
680 g.RecurseThroughSymlinksOff();
681 break;
682 case cmPolicies::OLD:
683 case cmPolicies::WARN:
684 case cmPolicies::REQUIRED_IF_USED:
685 case cmPolicies::REQUIRED_ALWAYS:
686 g.RecurseThroughSymlinksOn();
687 break;
691 std::string output = "";
692 bool first = true;
693 for ( ; i != args.end(); ++i )
695 if ( recurse && (*i == "FOLLOW_SYMLINKS") )
697 explicitFollowSymlinks = true;
698 g.RecurseThroughSymlinksOn();
699 ++i;
700 if ( i == args.end() )
702 this->SetError(
703 "GLOB_RECURSE requires a glob expression after FOLLOW_SYMLINKS");
704 return false;
708 if ( *i == "RELATIVE" )
710 ++i; // skip RELATIVE
711 if ( i == args.end() )
713 this->SetError("GLOB requires a directory after the RELATIVE tag");
714 return false;
716 g.SetRelative(i->c_str());
717 ++i;
718 if(i == args.end())
720 this->SetError("GLOB requires a glob expression after the directory");
721 return false;
725 if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
727 std::string expr = this->Makefile->GetCurrentDirectory();
728 // Handle script mode
729 if ( expr.size() > 0 )
731 expr += "/" + *i;
732 g.FindFiles(expr);
734 else
736 g.FindFiles(*i);
739 else
741 g.FindFiles(*i);
744 std::vector<std::string>::size_type cc;
745 std::vector<std::string>& files = g.GetFiles();
746 for ( cc = 0; cc < files.size(); cc ++ )
748 if ( !first )
750 output += ";";
752 output += files[cc];
753 first = false;
757 if(recurse && !explicitFollowSymlinks)
759 switch (status)
761 case cmPolicies::NEW:
762 // Correct behavior, yay!
763 break;
764 case cmPolicies::OLD:
765 // Probably not really the expected behavior, but the author explicitly
766 // asked for the old behavior... no warning.
767 case cmPolicies::WARN:
768 // Possibly unexpected old behavior *and* we actually traversed
769 // symlinks without being explicitly asked to: warn the author.
770 if(g.GetFollowedSymlinkCount() != 0)
772 this->Makefile->IssueMessage(cmake::AUTHOR_WARNING,
773 this->Makefile->GetPolicies()->
774 GetPolicyWarning(cmPolicies::CMP0009));
776 break;
777 case cmPolicies::REQUIRED_IF_USED:
778 case cmPolicies::REQUIRED_ALWAYS:
779 this->SetError("policy CMP0009 error");
780 this->Makefile->IssueMessage(cmake::FATAL_ERROR,
781 this->Makefile->GetPolicies()->
782 GetRequiredPolicyError(cmPolicies::CMP0009));
783 return false;
787 this->Makefile->AddDefinition(variable.c_str(), output.c_str());
788 return true;
791 //----------------------------------------------------------------------------
792 bool cmFileCommand::HandleMakeDirectoryCommand(
793 std::vector<std::string> const& args)
795 if(args.size() < 2 )
797 this->SetError("called with incorrect number of arguments");
798 return false;
801 std::vector<std::string>::const_iterator i = args.begin();
803 i++; // Get rid of subcommand
805 std::string expr;
806 for ( ; i != args.end(); ++i )
808 const std::string* cdir = &(*i);
809 if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
811 expr = this->Makefile->GetCurrentDirectory();
812 expr += "/" + *i;
813 cdir = &expr;
815 if ( !this->Makefile->CanIWriteThisFile(cdir->c_str()) )
817 std::string e = "attempted to create a directory: " + *cdir
818 + " into a source directory.";
819 this->SetError(e.c_str());
820 cmSystemTools::SetFatalErrorOccured();
821 return false;
823 if ( !cmSystemTools::MakeDirectory(cdir->c_str()) )
825 std::string error = "problem creating directory: " + *cdir;
826 this->SetError(error.c_str());
827 return false;
830 return true;
833 //----------------------------------------------------------------------------
834 // File installation helper class.
835 struct cmFileInstaller
837 // Methods to actually install files.
838 bool InstallFile(const char* fromFile, const char* toFile, bool always);
839 bool InstallDirectory(const char* source, const char* destination,
840 bool always);
842 // All instances need the file command and makefile using them.
843 cmFileInstaller(cmFileCommand* fc, cmMakefile* mf):
844 FileCommand(fc), Makefile(mf), DestDirLength(0), MatchlessFiles(true)
846 // Get the current manifest.
847 this->Manifest =
848 this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
850 ~cmFileInstaller()
852 // Save the updated install manifest.
853 this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
854 this->Manifest.c_str());
857 private:
858 cmFileCommand* FileCommand;
859 cmMakefile* Makefile;
860 cmFileTimeComparison FileTimes;
861 public:
863 // The length of the destdir setting.
864 int DestDirLength;
866 // Whether to install a file not matching any expression.
867 bool MatchlessFiles;
869 // The current file manifest (semicolon separated list).
870 std::string Manifest;
872 // Permissions for files and directories installed by this object.
873 mode_t FilePermissions;
874 mode_t DirPermissions;
876 // Properties set by pattern and regex match rules.
877 struct MatchProperties
879 bool Exclude;
880 mode_t Permissions;
881 MatchProperties(): Exclude(false), Permissions(0) {}
883 struct MatchRule
885 cmsys::RegularExpression Regex;
886 MatchProperties Properties;
887 std::string RegexString;
888 MatchRule(std::string const& regex):
889 Regex(regex.c_str()), RegexString(regex) {}
891 std::vector<MatchRule> MatchRules;
893 // Get the properties from rules matching this input file.
894 MatchProperties CollectMatchProperties(const char* file,
895 bool isDirectory)
897 // Match rules are case-insensitive on some platforms.
898 #if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
899 std::string lower = cmSystemTools::LowerCase(file);
900 file = lower.c_str();
901 #endif
903 // Collect properties from all matching rules.
904 bool matched = false;
905 MatchProperties result;
906 for(std::vector<MatchRule>::iterator mr = this->MatchRules.begin();
907 mr != this->MatchRules.end(); ++mr)
909 if(mr->Regex.find(file))
911 matched = true;
912 result.Exclude |= mr->Properties.Exclude;
913 result.Permissions |= mr->Properties.Permissions;
916 if(!matched && !this->MatchlessFiles && !isDirectory)
918 result.Exclude = true;
920 return result;
923 // Append a file to the installation manifest.
924 void ManifestAppend(std::string const& file)
926 this->Manifest += ";";
927 this->Manifest += file.substr(this->DestDirLength);
930 // Translate an argument to a permissions bit.
931 bool CheckPermissions(std::string const& arg, mode_t& permissions)
933 if(arg == "OWNER_READ") { permissions |= mode_owner_read; }
934 else if(arg == "OWNER_WRITE") { permissions |= mode_owner_write; }
935 else if(arg == "OWNER_EXECUTE") { permissions |= mode_owner_execute; }
936 else if(arg == "GROUP_READ") { permissions |= mode_group_read; }
937 else if(arg == "GROUP_WRITE") { permissions |= mode_group_write; }
938 else if(arg == "GROUP_EXECUTE") { permissions |= mode_group_execute; }
939 else if(arg == "WORLD_READ") { permissions |= mode_world_read; }
940 else if(arg == "WORLD_WRITE") { permissions |= mode_world_write; }
941 else if(arg == "WORLD_EXECUTE") { permissions |= mode_world_execute; }
942 else if(arg == "SETUID") { permissions |= mode_setuid; }
943 else if(arg == "SETGID") { permissions |= mode_setgid; }
944 else
946 cmOStringStream e;
947 e << "INSTALL given invalid permission \"" << arg << "\".";
948 this->FileCommand->SetError(e.str().c_str());
949 return false;
951 return true;
954 private:
955 bool InstallSymlink(const char* fromFile, const char* toFile, bool always);
958 //----------------------------------------------------------------------------
959 bool cmFileInstaller::InstallSymlink(const char* fromFile, const char* toFile,
960 bool always)
962 // Read the original symlink.
963 std::string symlinkTarget;
964 if(!cmSystemTools::ReadSymlink(fromFile, symlinkTarget))
966 cmOStringStream e;
967 e << "INSTALL cannot read symlink \"" << fromFile
968 << "\" to duplicate at \"" << toFile << "\".";
969 this->FileCommand->SetError(e.str().c_str());
970 return false;
973 // Compare the symlink value to that at the destination if not
974 // always installing.
975 bool copy = true;
976 if(!always)
978 std::string oldSymlinkTarget;
979 if(cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget))
981 if(symlinkTarget == oldSymlinkTarget)
983 copy = false;
988 // Inform the user about this file installation.
989 std::string message = (copy? "Installing: " : "Up-to-date: ");
990 message += toFile;
991 this->Makefile->DisplayStatus(message.c_str(), -1);
993 if(copy)
995 // Remove the destination file so we can always create the symlink.
996 cmSystemTools::RemoveFile(toFile);
998 // Create the symlink.
999 if(!cmSystemTools::CreateSymlink(symlinkTarget.c_str(), toFile))
1001 cmOStringStream e;
1002 e << "INSTALL cannot duplicate symlink \"" << fromFile
1003 << "\" at \"" << toFile << "\".";
1004 this->FileCommand->SetError(e.str().c_str());
1005 return false;
1009 // Add the file to the manifest.
1010 this->ManifestAppend(toFile);
1012 return true;
1015 //----------------------------------------------------------------------------
1016 bool cmFileInstaller::InstallFile(const char* fromFile, const char* toFile,
1017 bool always)
1019 // Collect any properties matching this file name.
1020 MatchProperties match_properties =
1021 this->CollectMatchProperties(fromFile, false);
1023 // Skip the file if it is excluded.
1024 if(match_properties.Exclude)
1026 return true;
1029 // Short-circuit for symbolic links.
1030 if(cmSystemTools::FileIsSymlink(fromFile))
1032 return this->InstallSymlink(fromFile, toFile, always);
1035 // Determine whether we will copy the file.
1036 bool copy = true;
1037 if(!always)
1039 // If both files exist with the same time do not copy.
1040 if(!this->FileTimes.FileTimesDiffer(fromFile, toFile))
1042 copy = false;
1046 // Inform the user about this file installation.
1047 std::string message = (copy? "Installing: " : "Up-to-date: ");
1048 message += toFile;
1049 this->Makefile->DisplayStatus(message.c_str(), -1);
1051 // Copy the file.
1052 if(copy && !cmSystemTools::CopyAFile(fromFile, toFile, true))
1054 cmOStringStream e;
1055 e << "INSTALL cannot copy file \"" << fromFile
1056 << "\" to \"" << toFile << "\".";
1057 this->FileCommand->SetError(e.str().c_str());
1058 return false;
1061 // Add the file to the manifest.
1062 this->ManifestAppend(toFile);
1064 // Set the file modification time of the destination file.
1065 if(copy && !always)
1067 cmSystemTools::CopyFileTime(fromFile, toFile);
1070 // Set permissions of the destination file.
1071 mode_t permissions = (match_properties.Permissions?
1072 match_properties.Permissions : this->FilePermissions);
1073 if(!permissions)
1075 // No permissions were explicitly provided but the user requested
1076 // that the source file permissions be used.
1077 cmSystemTools::GetPermissions(fromFile, permissions);
1079 if(permissions && !cmSystemTools::SetPermissions(toFile, permissions))
1081 cmOStringStream e;
1082 e << "Problem setting permissions on file \"" << toFile << "\"";
1083 this->FileCommand->SetError(e.str().c_str());
1084 return false;
1087 return true;
1090 //----------------------------------------------------------------------------
1091 bool cmFileInstaller::InstallDirectory(const char* source,
1092 const char* destination,
1093 bool always)
1095 // Collect any properties matching this directory name.
1096 MatchProperties match_properties =
1097 this->CollectMatchProperties(source, true);
1099 // Skip the directory if it is excluded.
1100 if(match_properties.Exclude)
1102 return true;
1105 // Short-circuit for symbolic links.
1106 if(cmSystemTools::FileIsSymlink(source))
1108 return this->InstallSymlink(source, destination, always);
1111 // Inform the user about this directory installation.
1112 std::string message = "Installing: ";
1113 message += destination;
1114 this->Makefile->DisplayStatus(message.c_str(), -1);
1116 // Make sure the destination directory exists.
1117 if(!cmSystemTools::MakeDirectory(destination))
1119 return false;
1122 // Compute the requested permissions for the destination directory.
1123 mode_t permissions = (match_properties.Permissions?
1124 match_properties.Permissions : this->DirPermissions);
1125 if(!permissions)
1127 // No permissions were explicitly provided but the user requested
1128 // that the source directory permissions be used.
1129 cmSystemTools::GetPermissions(source, permissions);
1132 // Compute the set of permissions required on this directory to
1133 // recursively install files and subdirectories safely.
1134 mode_t required_permissions =
1135 mode_owner_read | mode_owner_write | mode_owner_execute;
1137 // If the required permissions are specified it is safe to set the
1138 // final permissions now. Otherwise we must add the required
1139 // permissions temporarily during file installation.
1140 mode_t permissions_before = 0;
1141 mode_t permissions_after = 0;
1142 if(permissions & required_permissions)
1144 permissions_before = permissions;
1146 else
1148 permissions_before = permissions | required_permissions;
1149 permissions_after = permissions;
1152 // Set the required permissions of the destination directory.
1153 if(permissions_before &&
1154 !cmSystemTools::SetPermissions(destination, permissions_before))
1156 cmOStringStream e;
1157 e << "Problem setting permissions on directory \""
1158 << destination << "\"";
1159 this->FileCommand->SetError(e.str().c_str());
1160 return false;
1163 // Load the directory contents to traverse it recursively.
1164 cmsys::Directory dir;
1165 if(source && *source)
1167 dir.Load(source);
1169 unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
1170 for(unsigned long fileNum = 0; fileNum < numFiles; ++fileNum)
1172 if(!(strcmp(dir.GetFile(fileNum), ".") == 0 ||
1173 strcmp(dir.GetFile(fileNum), "..") == 0))
1175 cmsys_stl::string fromPath = source;
1176 fromPath += "/";
1177 fromPath += dir.GetFile(fileNum);
1178 if(cmSystemTools::FileIsDirectory(fromPath.c_str()))
1180 cmsys_stl::string toDir = destination;
1181 toDir += "/";
1182 toDir += dir.GetFile(fileNum);
1183 if(!this->InstallDirectory(fromPath.c_str(), toDir.c_str(), always))
1185 return false;
1188 else
1190 // Install this file.
1191 std::string toFile = destination;
1192 toFile += "/";
1193 toFile += dir.GetFile(fileNum);
1194 if(!this->InstallFile(fromPath.c_str(), toFile.c_str(), always))
1196 return false;
1202 // Set the requested permissions of the destination directory.
1203 if(permissions_after &&
1204 !cmSystemTools::SetPermissions(destination, permissions_after))
1206 cmOStringStream e;
1207 e << "Problem setting permissions on directory \"" << destination << "\"";
1208 this->FileCommand->SetError(e.str().c_str());
1209 return false;
1212 return true;
1215 //----------------------------------------------------------------------------
1216 void cmFileCommand::HandleInstallPermissions(cmFileInstaller& installer,
1217 mode_t& permissions_file,
1218 mode_t& permissions_dir,
1219 int itype,
1220 bool use_given_permissions_file,
1221 bool use_given_permissions_dir,
1222 bool use_source_permissions) const
1224 // Choose a default for shared library permissions.
1225 bool install_so_no_exe = this->Makefile->IsOn("CMAKE_INSTALL_SO_NO_EXE");
1226 // If file permissions were not specified set default permissions
1227 // for this target type.
1228 if(!use_given_permissions_file && !use_source_permissions)
1230 switch(itype)
1232 case cmTarget::SHARED_LIBRARY:
1233 case cmTarget::MODULE_LIBRARY:
1234 if(install_so_no_exe)
1236 // Use read/write permissions.
1237 permissions_file = 0;
1238 permissions_file |= mode_owner_read;
1239 permissions_file |= mode_owner_write;
1240 permissions_file |= mode_group_read;
1241 permissions_file |= mode_world_read;
1242 break;
1244 case cmTarget::EXECUTABLE:
1245 case cmTarget::INSTALL_PROGRAMS:
1246 // Use read/write/executable permissions.
1247 permissions_file = 0;
1248 permissions_file |= mode_owner_read;
1249 permissions_file |= mode_owner_write;
1250 permissions_file |= mode_owner_execute;
1251 permissions_file |= mode_group_read;
1252 permissions_file |= mode_group_execute;
1253 permissions_file |= mode_world_read;
1254 permissions_file |= mode_world_execute;
1255 break;
1256 default:
1257 // Use read/write permissions.
1258 permissions_file = 0;
1259 permissions_file |= mode_owner_read;
1260 permissions_file |= mode_owner_write;
1261 permissions_file |= mode_group_read;
1262 permissions_file |= mode_world_read;
1263 break;
1267 // If directory permissions were not specified set default permissions.
1268 if(!use_given_permissions_dir && !use_source_permissions)
1270 // Use read/write/executable permissions.
1271 permissions_dir = 0;
1272 permissions_dir |= mode_owner_read;
1273 permissions_dir |= mode_owner_write;
1274 permissions_dir |= mode_owner_execute;
1275 permissions_dir |= mode_group_read;
1276 permissions_dir |= mode_group_execute;
1277 permissions_dir |= mode_world_read;
1278 permissions_dir |= mode_world_execute;
1280 // Set the installer permissions.
1281 installer.FilePermissions = permissions_file;
1282 installer.DirPermissions = permissions_dir;
1285 //----------------------------------------------------------------------------
1286 void cmFileCommand
1287 ::GetTargetTypeFromString(const std::string& stype, int& itype) const
1289 if ( stype == "EXECUTABLE" )
1291 itype = cmTarget::EXECUTABLE;
1293 else if ( stype == "PROGRAM" )
1295 itype = cmTarget::INSTALL_PROGRAMS;
1297 else if ( stype == "STATIC_LIBRARY" )
1299 itype = cmTarget::STATIC_LIBRARY;
1301 else if ( stype == "SHARED_LIBRARY" )
1303 itype = cmTarget::SHARED_LIBRARY;
1305 else if ( stype == "MODULE" )
1307 itype = cmTarget::MODULE_LIBRARY;
1309 else if ( stype == "DIRECTORY" )
1311 itype = cmTarget::INSTALL_DIRECTORY;
1316 //----------------------------------------------------------------------------
1317 bool cmFileCommand::HandleInstallDestination(cmFileInstaller& installer,
1318 std::string& destination)
1320 // allow for / to be a valid destination
1321 if ( destination.size() < 2 && destination != "/" )
1323 this->SetError("called with inapropriate arguments. "
1324 "No DESTINATION provided or .");
1325 return false;
1328 const char* destdir = cmSystemTools::GetEnv("DESTDIR");
1329 if ( destdir && *destdir )
1331 std::string sdestdir = destdir;
1332 cmSystemTools::ConvertToUnixSlashes(sdestdir);
1333 char ch1 = destination[0];
1334 char ch2 = destination[1];
1335 char ch3 = 0;
1336 if ( destination.size() > 2 )
1338 ch3 = destination[2];
1340 int skip = 0;
1341 if ( ch1 != '/' )
1343 int relative = 0;
1344 if ( ( ch1 >= 'a' && ch1 <= 'z' || ch1 >= 'A' && ch1 <= 'Z' ) &&
1345 ch2 == ':' )
1347 // Assume windows
1348 // let's do some destdir magic:
1349 skip = 2;
1350 if ( ch3 != '/' )
1352 relative = 1;
1355 else
1357 relative = 1;
1359 if ( relative )
1361 // This is relative path on unix or windows. Since we are doing
1362 // destdir, this case does not make sense.
1363 this->SetError("called with relative DESTINATION. This "
1364 "does not make sense when using DESTDIR. Specify "
1365 "absolute path or remove DESTDIR environment variable.");
1366 return false;
1369 else
1371 if ( ch2 == '/' )
1373 // looks like a network path.
1374 std::string message = "called with network path DESTINATION. This "
1375 "does not make sense when using DESTDIR. Specify local "
1376 "absolute path or remove DESTDIR environment variable."
1377 "\nDESTINATION=\n";
1378 message += destination;
1379 this->SetError(message.c_str());
1380 return false;
1383 destination = sdestdir + (destination.c_str() + skip);
1384 installer.DestDirLength = int(sdestdir.size());
1387 if ( !cmSystemTools::FileExists(destination.c_str()) )
1389 if ( !cmSystemTools::MakeDirectory(destination.c_str()) )
1391 std::string errstring = "cannot create directory: " + destination +
1392 ". Maybe need administrative privileges.";
1393 this->SetError(errstring.c_str());
1394 return false;
1397 if ( !cmSystemTools::FileIsDirectory(destination.c_str()) )
1399 std::string errstring = "INSTALL destination: " + destination +
1400 " is not a directory.";
1401 this->SetError(errstring.c_str());
1402 return false;
1404 return true;
1407 //----------------------------------------------------------------------------
1408 bool
1409 cmFileCommand::HandleRPathChangeCommand(std::vector<std::string> const& args)
1411 // Evaluate arguments.
1412 const char* file = 0;
1413 const char* oldRPath = 0;
1414 const char* newRPath = 0;
1415 enum Doing { DoingNone, DoingFile, DoingOld, DoingNew };
1416 Doing doing = DoingNone;
1417 for(unsigned int i=1; i < args.size(); ++i)
1419 if(args[i] == "OLD_RPATH")
1421 doing = DoingOld;
1423 else if(args[i] == "NEW_RPATH")
1425 doing = DoingNew;
1427 else if(args[i] == "FILE")
1429 doing = DoingFile;
1431 else if(doing == DoingFile)
1433 file = args[i].c_str();
1434 doing = DoingNone;
1436 else if(doing == DoingOld)
1438 oldRPath = args[i].c_str();
1439 doing = DoingNone;
1441 else if(doing == DoingNew)
1443 newRPath = args[i].c_str();
1444 doing = DoingNone;
1446 else
1448 cmOStringStream e;
1449 e << "RPATH_CHANGE given unknown argument " << args[i];
1450 this->SetError(e.str().c_str());
1451 return false;
1454 if(!file)
1456 this->SetError("RPATH_CHANGE not given FILE option.");
1457 return false;
1459 if(!oldRPath)
1461 this->SetError("RPATH_CHANGE not given OLD_RPATH option.");
1462 return false;
1464 if(!newRPath)
1466 this->SetError("RPATH_CHANGE not given NEW_RPATH option.");
1467 return false;
1469 if(!cmSystemTools::FileExists(file, true))
1471 cmOStringStream e;
1472 e << "RPATH_CHANGE given FILE \"" << file << "\" that does not exist.";
1473 this->SetError(e.str().c_str());
1474 return false;
1476 bool success = true;
1477 cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
1478 bool have_ft = cmSystemTools::FileTimeGet(file, ft);
1479 std::string emsg;
1480 bool changed;
1481 if(!cmSystemTools::ChangeRPath(file, oldRPath, newRPath, &emsg, &changed))
1483 cmOStringStream e;
1484 e << "RPATH_CHANGE could not write new RPATH:\n"
1485 << " " << newRPath << "\n"
1486 << "to the file:\n"
1487 << " " << file << "\n"
1488 << emsg;
1489 this->SetError(e.str().c_str());
1490 success = false;
1492 if(success)
1494 if(changed)
1496 std::string message = "Set runtime path of \"";
1497 message += file;
1498 message += "\" to \"";
1499 message += newRPath;
1500 message += "\"";
1501 this->Makefile->DisplayStatus(message.c_str(), -1);
1503 if(have_ft)
1505 cmSystemTools::FileTimeSet(file, ft);
1508 cmSystemTools::FileTimeDelete(ft);
1509 return success;
1512 //----------------------------------------------------------------------------
1513 bool
1514 cmFileCommand::HandleRPathRemoveCommand(std::vector<std::string> const& args)
1516 // Evaluate arguments.
1517 const char* file = 0;
1518 enum Doing { DoingNone, DoingFile };
1519 Doing doing = DoingNone;
1520 for(unsigned int i=1; i < args.size(); ++i)
1522 if(args[i] == "FILE")
1524 doing = DoingFile;
1526 else if(doing == DoingFile)
1528 file = args[i].c_str();
1529 doing = DoingNone;
1531 else
1533 cmOStringStream e;
1534 e << "RPATH_REMOVE given unknown argument " << args[i];
1535 this->SetError(e.str().c_str());
1536 return false;
1539 if(!file)
1541 this->SetError("RPATH_REMOVE not given FILE option.");
1542 return false;
1544 if(!cmSystemTools::FileExists(file, true))
1546 cmOStringStream e;
1547 e << "RPATH_REMOVE given FILE \"" << file << "\" that does not exist.";
1548 this->SetError(e.str().c_str());
1549 return false;
1551 bool success = true;
1552 cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
1553 bool have_ft = cmSystemTools::FileTimeGet(file, ft);
1554 std::string emsg;
1555 bool removed;
1556 if(!cmSystemTools::RemoveRPath(file, &emsg, &removed))
1558 cmOStringStream e;
1559 e << "RPATH_REMOVE could not remove RPATH from file:\n"
1560 << " " << file << "\n"
1561 << emsg;
1562 this->SetError(e.str().c_str());
1563 success = false;
1565 if(success)
1567 if(removed)
1569 std::string message = "Removed runtime path from \"";
1570 message += file;
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::HandleRPathCheckCommand(std::vector<std::string> const& args)
1587 // Evaluate arguments.
1588 const char* file = 0;
1589 const char* rpath = 0;
1590 enum Doing { DoingNone, DoingFile, DoingRPath };
1591 Doing doing = DoingNone;
1592 for(unsigned int i=1; i < args.size(); ++i)
1594 if(args[i] == "RPATH")
1596 doing = DoingRPath;
1598 else if(args[i] == "FILE")
1600 doing = DoingFile;
1602 else if(doing == DoingFile)
1604 file = args[i].c_str();
1605 doing = DoingNone;
1607 else if(doing == DoingRPath)
1609 rpath = args[i].c_str();
1610 doing = DoingNone;
1612 else
1614 cmOStringStream e;
1615 e << "RPATH_CHECK given unknown argument " << args[i];
1616 this->SetError(e.str().c_str());
1617 return false;
1620 if(!file)
1622 this->SetError("RPATH_CHECK not given FILE option.");
1623 return false;
1625 if(!rpath)
1627 this->SetError("RPATH_CHECK not given RPATH option.");
1628 return false;
1631 // If the file exists but does not have the desired RPath then
1632 // delete it. This is used during installation to re-install a file
1633 // if its RPath will change.
1634 if(cmSystemTools::FileExists(file, true) &&
1635 !cmSystemTools::CheckRPath(file, rpath))
1637 cmSystemTools::RemoveFile(file);
1640 return true;
1643 //----------------------------------------------------------------------------
1644 bool cmFileCommand::HandleInstallCommand(std::vector<std::string> const& args)
1646 if ( args.size() < 6 )
1648 this->SetError("called with incorrect number of arguments");
1649 return false;
1652 // Construct a file installer object.
1653 cmFileInstaller installer(this, this->Makefile);
1655 std::string rename = "";
1656 std::string destination = "";
1658 std::vector<std::string> files;
1659 int itype = cmTarget::INSTALL_FILES;
1661 std::map<cmStdString, const char*> properties;
1662 bool optional = false;
1663 bool result = this->ParseInstallArgs(args, installer, properties,
1664 itype, rename, destination, files,
1665 optional);
1666 if (result == true)
1668 result = this->DoInstall(installer,
1669 itype, rename, destination, files, optional);
1671 return result;
1674 //----------------------------------------------------------------------------
1675 bool cmFileCommand::ParseInstallArgs(std::vector<std::string> const& args,
1676 cmFileInstaller& installer,
1677 std::map<cmStdString, const char*>& properties,
1678 int& itype,
1679 std::string& rename,
1680 std::string& destination,
1681 std::vector<std::string>& files,
1682 bool& optional)
1684 std::string stype = "FILES";
1685 bool doing_files = false;
1686 bool doing_properties = false;
1687 bool doing_permissions_file = false;
1688 bool doing_permissions_dir = false;
1689 bool doing_permissions_match = false;
1690 bool use_given_permissions_file = false;
1691 bool use_given_permissions_dir = false;
1692 bool use_source_permissions = false;
1693 mode_t permissions_file = 0;
1694 mode_t permissions_dir = 0;
1696 cmFileInstaller::MatchRule* current_match_rule = 0;
1697 std::vector<std::string>::size_type i = 0;
1698 i++; // Get rid of subcommand
1699 for ( ; i != args.size(); ++i )
1701 const std::string* cstr = &args[i];
1702 if ( *cstr == "DESTINATION" && i < args.size()-1 )
1704 if(current_match_rule)
1706 cmOStringStream e;
1707 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1708 this->SetError(e.str().c_str());
1709 return false;
1712 i++;
1713 destination = args[i];
1714 doing_files = false;
1715 doing_properties = false;
1716 doing_permissions_file = false;
1717 doing_permissions_dir = false;
1719 else if ( *cstr == "TYPE" && i < args.size()-1 )
1721 if(current_match_rule)
1723 cmOStringStream e;
1724 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1725 this->SetError(e.str().c_str());
1726 return false;
1729 i++;
1730 stype = args[i];
1731 if ( args[i+1] == "OPTIONAL" )
1733 i++;
1734 optional = true;
1736 doing_properties = false;
1737 doing_files = false;
1738 doing_permissions_file = false;
1739 doing_permissions_dir = false;
1741 else if ( *cstr == "RENAME" && i < args.size()-1 )
1743 if(current_match_rule)
1745 cmOStringStream e;
1746 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1747 this->SetError(e.str().c_str());
1748 return false;
1751 i++;
1752 rename = args[i];
1753 doing_properties = false;
1754 doing_files = false;
1755 doing_permissions_file = false;
1756 doing_permissions_dir = false;
1758 else if ( *cstr == "REGEX" && i < args.size()-1 )
1760 i++;
1761 installer.MatchRules.push_back(cmFileInstaller::MatchRule(args[i]));
1762 current_match_rule = &*(installer.MatchRules.end()-1);
1763 if(!current_match_rule->Regex.is_valid())
1765 cmOStringStream e;
1766 e << "INSTALL could not compile REGEX \"" << args[i] << "\".";
1767 this->SetError(e.str().c_str());
1768 return false;
1770 doing_properties = false;
1771 doing_files = false;
1772 doing_permissions_file = false;
1773 doing_permissions_dir = false;
1775 else if ( *cstr == "EXCLUDE" )
1777 // Add this property to the current match rule.
1778 if(!current_match_rule)
1780 cmOStringStream e;
1781 e << "INSTALL does not allow \""
1782 << *cstr << "\" before a REGEX is given.";
1783 this->SetError(e.str().c_str());
1784 return false;
1786 current_match_rule->Properties.Exclude = true;
1787 doing_permissions_match = true;
1789 else if ( *cstr == "PROPERTIES" )
1791 if(current_match_rule)
1793 cmOStringStream e;
1794 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1795 this->SetError(e.str().c_str());
1796 return false;
1799 doing_properties = true;
1800 doing_files = false;
1801 doing_permissions_file = false;
1802 doing_permissions_dir = false;
1804 else if ( *cstr == "PERMISSIONS" )
1806 if(current_match_rule)
1808 doing_permissions_match = true;
1809 doing_permissions_file = false;
1811 else
1813 doing_permissions_match = false;
1814 doing_permissions_file = true;
1815 use_given_permissions_file = true;
1817 doing_properties = false;
1818 doing_files = false;
1819 doing_permissions_dir = false;
1821 else if ( *cstr == "DIR_PERMISSIONS" )
1823 if(current_match_rule)
1825 cmOStringStream e;
1826 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1827 this->SetError(e.str().c_str());
1828 return false;
1831 use_given_permissions_dir = true;
1832 doing_properties = false;
1833 doing_files = false;
1834 doing_permissions_file = false;
1835 doing_permissions_dir = true;
1837 else if ( *cstr == "USE_SOURCE_PERMISSIONS" )
1839 if(current_match_rule)
1841 cmOStringStream e;
1842 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1843 this->SetError(e.str().c_str());
1844 return false;
1847 doing_properties = false;
1848 doing_files = false;
1849 doing_permissions_file = false;
1850 doing_permissions_dir = false;
1851 use_source_permissions = true;
1853 else if ( *cstr == "FILES_MATCHING" )
1855 if(current_match_rule)
1857 cmOStringStream e;
1858 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1859 this->SetError(e.str().c_str());
1860 return false;
1863 doing_properties = false;
1864 doing_files = false;
1865 doing_permissions_file = false;
1866 doing_permissions_dir = false;
1867 installer.MatchlessFiles = false;
1869 else if ( *cstr == "COMPONENTS" )
1871 cmOStringStream e;
1872 e << "INSTALL called with old-style COMPONENTS argument. "
1873 << "This script was generated with an older version of CMake. "
1874 << "Re-run this cmake version on your build tree.";
1875 this->SetError(e.str().c_str());
1876 return false;
1878 else if ( *cstr == "CONFIGURATIONS" )
1880 cmOStringStream e;
1881 e << "INSTALL called with old-style CONFIGURATIONS argument. "
1882 << "This script was generated with an older version of CMake. "
1883 << "Re-run this cmake version on your build tree.";
1884 this->SetError(e.str().c_str());
1885 return false;
1887 else if ( *cstr == "FILES" && !doing_files)
1889 if(current_match_rule)
1891 cmOStringStream e;
1892 e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
1893 this->SetError(e.str().c_str());
1894 return false;
1897 doing_files = true;
1898 doing_properties = false;
1899 doing_permissions_file = false;
1900 doing_permissions_dir = false;
1902 else if ( doing_properties && i < args.size()-1 )
1904 properties[args[i]] = args[i+1].c_str();
1905 i++;
1907 else if ( doing_files )
1909 files.push_back(*cstr);
1911 else if(doing_permissions_file)
1913 if(!installer.CheckPermissions(args[i], permissions_file))
1915 return false;
1918 else if(doing_permissions_dir)
1920 if(!installer.CheckPermissions(args[i], permissions_dir))
1922 return false;
1925 else if(doing_permissions_match)
1927 if(!installer.CheckPermissions(
1928 args[i], current_match_rule->Properties.Permissions))
1930 return false;
1933 else
1935 this->SetError("called with inappropriate arguments");
1936 return false;
1940 // now check and postprocess what has been parsed
1941 if ( files.size() == 0 )
1943 // nothing to do, no files were listed.
1944 // if this is handled as error, INSTALL_FILES() creates an invalid
1945 // cmake_install.cmake script with no FILES() arguments if no files were
1946 // given to INSTALL_FILES(). This was accepted with CMake 2.4.x.
1947 return true;
1950 // Check rename form.
1951 if(!rename.empty())
1953 if(itype != cmTarget::INSTALL_FILES &&
1954 itype != cmTarget::INSTALL_PROGRAMS)
1956 this->SetError("INSTALL option RENAME may be used only with "
1957 "FILES or PROGRAMS.");
1958 return false;
1960 if(files.size() > 1)
1962 this->SetError("INSTALL option RENAME may be used only with "
1963 "one file.");
1964 return false;
1968 if (this->HandleInstallDestination(installer, destination) == false)
1970 return false;
1973 if(properties.find("VERSION") != properties.end())
1975 cmOStringStream e;
1976 e << "INSTALL called with old-style VERSION property. "
1977 << "This script was generated with an older version of CMake. "
1978 << "Re-run this cmake version on your build tree.";
1979 this->SetError(e.str().c_str());
1980 return false;
1982 if(properties.find("SOVERSION") != properties.end())
1984 cmOStringStream e;
1985 e << "INSTALL called with old-style SOVERSION property. "
1986 << "This script was generated with an older version of CMake. "
1987 << "Re-run this cmake version on your build tree.";
1988 this->SetError(e.str().c_str());
1989 return false;
1992 this->GetTargetTypeFromString(stype, itype);
1994 this->HandleInstallPermissions(installer,
1995 permissions_file,
1996 permissions_dir,
1997 itype,
1998 use_given_permissions_file,
1999 use_given_permissions_dir,
2000 use_source_permissions);
2002 return true;
2005 //----------------------------------------------------------------------------
2006 bool cmFileCommand::DoInstall( cmFileInstaller& installer,
2007 const int itype,
2008 const std::string& rename,
2009 const std::string& destination,
2010 const std::vector<std::string>& files,
2011 const bool optional)
2013 typedef std::set<cmStdString>::const_iterator iter_type;
2015 // Check whether files should be copied always or only if they have
2016 // changed.
2017 bool copy_always =
2018 cmSystemTools::IsOn(cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS"));
2020 // Handle each file listed.
2021 for (std::vector<std::string>::size_type i = 0; i < files.size(); i ++ )
2023 // Split the input file into its directory and name components.
2024 std::vector<std::string> fromPathComponents;
2025 cmSystemTools::SplitPath(files[i].c_str(), fromPathComponents);
2026 std::string fromName = *(fromPathComponents.end()-1);
2027 std::string fromDir = cmSystemTools::JoinPath(fromPathComponents.begin(),
2028 fromPathComponents.end()-1);
2030 // Compute the full path to the destination file.
2031 std::string toFile = destination;
2032 std::string const& toName = rename.empty()? fromName : rename;
2033 if(!toName.empty())
2035 toFile += "/";
2036 toFile += toName;
2039 // Construct the full path to the source file. The file name may
2040 // have been changed above.
2041 std::string fromFile = fromDir;
2042 if(!fromName.empty())
2044 fromFile += "/";
2045 fromFile += fromName;
2048 std::string message;
2049 if(!cmSystemTools::SameFile(fromFile.c_str(), toFile.c_str()))
2051 if(itype == cmTarget::INSTALL_DIRECTORY &&
2052 (fromFile.empty() ||
2053 cmSystemTools::FileIsDirectory(fromFile.c_str())))
2055 // Try installing this directory.
2056 if(!installer.InstallDirectory(fromFile.c_str(), toFile.c_str(),
2057 copy_always))
2059 return false;
2062 else if(cmSystemTools::FileExists(fromFile.c_str()))
2064 // Install this file.
2065 if(!installer.InstallFile(fromFile.c_str(), toFile.c_str(),
2066 copy_always))
2068 return false;
2071 else if(!optional)
2073 // The input file does not exist and installation is not optional.
2074 cmOStringStream e;
2075 e << "INSTALL cannot find file \"" << fromFile << "\" to install.";
2076 this->SetError(e.str().c_str());
2077 return false;
2082 return true;
2085 //----------------------------------------------------------------------------
2086 bool cmFileCommand::HandleRelativePathCommand(
2087 std::vector<std::string> const& args)
2089 if(args.size() != 4 )
2091 this->SetError("called with incorrect number of arguments");
2092 return false;
2095 const std::string& outVar = args[1];
2096 const std::string& directoryName = args[2];
2097 const std::string& fileName = args[3];
2099 if(!cmSystemTools::FileIsFullPath(directoryName.c_str()))
2101 std::string errstring =
2102 "RelativePath must be passed a full path to the directory: "
2103 + directoryName;
2104 this->SetError(errstring.c_str());
2105 return false;
2107 if(!cmSystemTools::FileIsFullPath(fileName.c_str()))
2109 std::string errstring =
2110 "RelativePath must be passed a full path to the file: "
2111 + fileName;
2112 this->SetError(errstring.c_str());
2113 return false;
2116 std::string res = cmSystemTools::RelativePath(directoryName.c_str(),
2117 fileName.c_str());
2118 this->Makefile->AddDefinition(outVar.c_str(),
2119 res.c_str());
2120 return true;
2124 //----------------------------------------------------------------------------
2125 bool cmFileCommand::HandleRemove(std::vector<std::string> const& args,
2126 bool recurse)
2129 std::string message;
2130 std::vector<std::string>::const_iterator i = args.begin();
2132 i++; // Get rid of subcommand
2133 for(;i != args.end(); ++i)
2135 if(cmSystemTools::FileIsDirectory(i->c_str()) && recurse)
2137 cmSystemTools::RemoveADirectory(i->c_str());
2139 else
2141 cmSystemTools::RemoveFile(i->c_str());
2144 return true;
2147 //----------------------------------------------------------------------------
2148 bool cmFileCommand::HandleCMakePathCommand(std::vector<std::string>
2149 const& args,
2150 bool nativePath)
2152 std::vector<std::string>::const_iterator i = args.begin();
2153 if(args.size() != 3)
2155 this->SetError("FILE(SYSTEM_PATH ENV result) must be called with "
2156 "only three arguments.");
2157 return false;
2159 i++; // Get rid of subcommand
2160 #if defined(_WIN32) && !defined(__CYGWIN__)
2161 char pathSep = ';';
2162 #else
2163 char pathSep = ':';
2164 #endif
2165 std::vector<cmsys::String> path = cmSystemTools::SplitString(i->c_str(),
2166 pathSep);
2167 i++;
2168 const char* var = i->c_str();
2169 std::string value;
2170 for(std::vector<cmsys::String>::iterator j = path.begin();
2171 j != path.end(); ++j)
2173 if(j != path.begin())
2175 value += ";";
2177 if(!nativePath)
2179 cmSystemTools::ConvertToUnixSlashes(*j);
2181 else
2183 *j = cmSystemTools::ConvertToOutputPath(j->c_str());
2184 // remove double quotes in the path
2185 cmsys::String& s = *j;
2187 if(s.size() > 1 && s[0] == '\"' && s[s.size()-1] == '\"')
2189 s = s.substr(1,s.size()-2);
2192 value += *j;
2194 this->Makefile->AddDefinition(var, value.c_str());
2195 return true;
2197 #if defined(CMAKE_BUILD_WITH_CMAKE)
2199 // Stuff for curl download
2200 typedef std::vector<char> cmFileCommandVectorOfChar;
2201 namespace{
2202 size_t
2203 cmFileCommandWriteMemoryCallback(void *ptr, size_t size, size_t nmemb,
2204 void *data)
2206 register int realsize = (int)(size * nmemb);
2207 std::ofstream* fout = static_cast<std::ofstream*>(data);
2208 const char* chPtr = static_cast<char*>(ptr);
2209 fout->write(chPtr, realsize);
2210 return realsize;
2213 static size_t
2214 cmFileCommandCurlDebugCallback(CURL *, curl_infotype, char *chPtr,
2215 size_t size, void *data)
2217 cmFileCommandVectorOfChar *vec
2218 = static_cast<cmFileCommandVectorOfChar*>(data);
2219 vec->insert(vec->end(), chPtr, chPtr + size);
2221 return size;
2227 #endif
2229 bool
2230 cmFileCommand::HandleDownloadCommand(std::vector<std::string>
2231 const& args)
2233 #if defined(CMAKE_BUILD_WITH_CMAKE)
2234 std::vector<std::string>::const_iterator i = args.begin();
2235 if(args.size() < 3)
2237 this->SetError("FILE(DOWNLOAD url file) must be called with "
2238 "at least three arguments.");
2239 return false;
2241 i++; // Get rid of subcommand
2242 std::string url = *i;
2243 i++;
2244 std::string file = *i;
2245 i++;
2246 double timeout = 0;
2247 std::string verboseLog;
2248 std::string statusVar;
2249 while(i != args.end())
2251 if(*i == "TIMEOUT")
2253 i++;
2254 if(i != args.end())
2256 timeout = atof(i->c_str());
2258 else
2260 this->SetError("FILE(DOWNLOAD url file TIMEOUT time) missing "
2261 "time for TIMEOUT.");
2262 return false;
2265 else if(*i == "LOG")
2267 i++;
2268 if( i == args.end())
2270 this->SetError("FILE(DOWNLOAD url file LOG VAR) missing "
2271 "VAR for LOG.");
2272 return false;
2274 verboseLog = *i;
2276 else if(*i == "STATUS")
2278 i++;
2279 if( i == args.end())
2281 this->SetError("FILE(DOWNLOAD url file STATUS VAR) missing "
2282 "VAR for STATUS.");
2283 return false;
2285 statusVar = *i;
2287 i++;
2290 std::string dir = cmSystemTools::GetFilenamePath(file.c_str());
2291 if(!cmSystemTools::FileExists(dir.c_str()) &&
2292 !cmSystemTools::MakeDirectory(dir.c_str()))
2294 std::string errstring = "FILE(DOWNLOAD ) error; cannot create directory: "
2295 + dir + ". Maybe need administrative privileges.";
2296 this->SetError(errstring.c_str());
2297 return false;
2300 std::ofstream fout(file.c_str(), std::ios::binary);
2301 if(!fout)
2303 this->SetError("FILE(DOWNLOAD url file TIMEOUT time) can not open "
2304 "file for write.");
2305 return false;
2307 CURL *curl;
2308 curl_global_init(CURL_GLOBAL_DEFAULT);
2309 curl = curl_easy_init();
2310 if(!curl)
2312 this->SetError("FILE(DOWNLOAD ) error "
2313 "initializing curl.");
2314 return false;
2317 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
2318 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
2319 cmFileCommandWriteMemoryCallback);
2320 curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
2321 cmFileCommandCurlDebugCallback);
2322 cmFileCommandVectorOfChar chunkDebug;
2323 ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&fout);
2324 ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
2325 if(verboseLog.size())
2327 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
2329 if(timeout > 0)
2331 curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout );
2333 CURLcode res = curl_easy_perform(curl);
2334 /* always cleanup */
2335 curl_easy_cleanup(curl);
2336 if(statusVar.size())
2338 cmOStringStream result;
2339 result << (int)res << ";\"" << curl_easy_strerror(res) << "\"";
2340 this->Makefile->AddDefinition(statusVar.c_str(),
2341 result.str().c_str());
2343 curl_global_cleanup();
2344 if(chunkDebug.size())
2346 chunkDebug.push_back(0);
2347 if(CURLE_OPERATION_TIMEOUTED == res)
2349 std::string output = &*chunkDebug.begin();
2351 if(verboseLog.size())
2353 this->Makefile->AddDefinition(verboseLog.c_str(),
2354 &*chunkDebug.begin());
2358 this->Makefile->AddDefinition(verboseLog.c_str(),
2359 &*chunkDebug.begin());
2361 return true;
2362 #else
2363 this->SetError("FILE(DOWNLOAD ) "
2364 "not supported in bootstrap cmake ");
2365 return false;
2366 #endif