Imported Upstream version 2.8.12.2
[platform/upstream/cmake.git] / Source / cmFileCommand.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the License for more information.
11 ============================================================================*/
12 #include "cmFileCommand.h"
13 #include "cmCryptoHash.h"
14 #include "cmake.h"
15 #include "cmHexFileConverter.h"
16 #include "cmInstallType.h"
17 #include "cmFileTimeComparison.h"
18 #include "cmCryptoHash.h"
19
20 #include "cmTimestamp.h"
21
22 #if defined(CMAKE_BUILD_WITH_CMAKE)
23 #include "cm_curl.h"
24 #endif
25
26 #undef GetCurrentDirectory
27 #include <assert.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30
31 #include <cmsys/auto_ptr.hxx>
32 #include <cmsys/Directory.hxx>
33 #include <cmsys/Glob.hxx>
34 #include <cmsys/RegularExpression.hxx>
35
36 // Table of permissions flags.
37 #if defined(_WIN32) && !defined(__CYGWIN__)
38 static mode_t mode_owner_read = S_IREAD;
39 static mode_t mode_owner_write = S_IWRITE;
40 static mode_t mode_owner_execute = S_IEXEC;
41 static mode_t mode_group_read = 0;
42 static mode_t mode_group_write = 0;
43 static mode_t mode_group_execute = 0;
44 static mode_t mode_world_read = 0;
45 static mode_t mode_world_write = 0;
46 static mode_t mode_world_execute = 0;
47 static mode_t mode_setuid = 0;
48 static mode_t mode_setgid = 0;
49 #else
50 static mode_t mode_owner_read = S_IRUSR;
51 static mode_t mode_owner_write = S_IWUSR;
52 static mode_t mode_owner_execute = S_IXUSR;
53 static mode_t mode_group_read = S_IRGRP;
54 static mode_t mode_group_write = S_IWGRP;
55 static mode_t mode_group_execute = S_IXGRP;
56 static mode_t mode_world_read = S_IROTH;
57 static mode_t mode_world_write = S_IWOTH;
58 static mode_t mode_world_execute = S_IXOTH;
59 static mode_t mode_setuid = S_ISUID;
60 static mode_t mode_setgid = S_ISGID;
61 #endif
62
63 // cmLibraryCommand
64 bool cmFileCommand
65 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
66 {
67   if(args.size() < 2 )
68     {
69     this->SetError("must be called with at least two arguments.");
70     return false;
71     }
72   std::string subCommand = args[0];
73   if ( subCommand == "WRITE" )
74     {
75     return this->HandleWriteCommand(args, false);
76     }
77   else if ( subCommand == "APPEND" )
78     {
79     return this->HandleWriteCommand(args, true);
80     }
81   else if ( subCommand == "DOWNLOAD" )
82     {
83     return this->HandleDownloadCommand(args);
84     }
85   else if ( subCommand == "UPLOAD" )
86     {
87     return this->HandleUploadCommand(args);
88     }
89   else if ( subCommand == "READ" )
90     {
91     return this->HandleReadCommand(args);
92     }
93   else if ( subCommand == "MD5" ||
94             subCommand == "SHA1" ||
95             subCommand == "SHA224" ||
96             subCommand == "SHA256" ||
97             subCommand == "SHA384" ||
98             subCommand == "SHA512" )
99     {
100     return this->HandleHashCommand(args);
101     }
102   else if ( subCommand == "STRINGS" )
103     {
104     return this->HandleStringsCommand(args);
105     }
106   else if ( subCommand == "GLOB" )
107     {
108     return this->HandleGlobCommand(args, false);
109     }
110   else if ( subCommand == "GLOB_RECURSE" )
111     {
112     return this->HandleGlobCommand(args, true);
113     }
114   else if ( subCommand == "MAKE_DIRECTORY" )
115     {
116     return this->HandleMakeDirectoryCommand(args);
117     }
118   else if ( subCommand == "RENAME" )
119     {
120     return this->HandleRename(args);
121     }
122   else if ( subCommand == "REMOVE" )
123     {
124     return this->HandleRemove(args, false);
125     }
126   else if ( subCommand == "REMOVE_RECURSE" )
127     {
128     return this->HandleRemove(args, true);
129     }
130   else if ( subCommand == "COPY" )
131     {
132     return this->HandleCopyCommand(args);
133     }
134   else if ( subCommand == "INSTALL" )
135     {
136     return this->HandleInstallCommand(args);
137     }
138   else if ( subCommand == "DIFFERENT" )
139     {
140     return this->HandleDifferentCommand(args);
141     }
142   else if ( subCommand == "RPATH_CHANGE" || subCommand == "CHRPATH" )
143     {
144     return this->HandleRPathChangeCommand(args);
145     }
146   else if ( subCommand == "RPATH_CHECK" )
147     {
148     return this->HandleRPathCheckCommand(args);
149     }
150   else if ( subCommand == "RPATH_REMOVE" )
151     {
152     return this->HandleRPathRemoveCommand(args);
153     }
154   else if ( subCommand == "RELATIVE_PATH" )
155     {
156     return this->HandleRelativePathCommand(args);
157     }
158   else if ( subCommand == "TO_CMAKE_PATH" )
159     {
160     return this->HandleCMakePathCommand(args, false);
161     }
162   else if ( subCommand == "TO_NATIVE_PATH" )
163     {
164     return this->HandleCMakePathCommand(args, true);
165     }
166   else if ( subCommand == "TIMESTAMP" )
167     {
168     return this->HandleTimestampCommand(args);
169     }
170   else if ( subCommand == "GENERATE" )
171     {
172     return this->HandleGenerateCommand(args);
173     }
174
175   std::string e = "does not recognize sub-command "+subCommand;
176   this->SetError(e.c_str());
177   return false;
178 }
179
180 //----------------------------------------------------------------------------
181 bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args,
182   bool append)
183 {
184   std::string message;
185   std::vector<std::string>::const_iterator i = args.begin();
186
187   i++; // Get rid of subcommand
188
189   std::string fileName = *i;
190   if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
191     {
192     fileName = this->Makefile->GetCurrentDirectory();
193     fileName += "/" + *i;
194     }
195
196   i++;
197
198   for(;i != args.end(); ++i)
199     {
200     message += *i;
201     }
202   if ( !this->Makefile->CanIWriteThisFile(fileName.c_str()) )
203     {
204     std::string e
205       = "attempted to write a file: " + fileName +
206       " into a source directory.";
207     this->SetError(e.c_str());
208     cmSystemTools::SetFatalErrorOccured();
209     return false;
210     }
211   std::string dir = cmSystemTools::GetFilenamePath(fileName);
212   cmSystemTools::MakeDirectory(dir.c_str());
213
214   mode_t mode = 0;
215
216   // Set permissions to writable
217   if ( cmSystemTools::GetPermissions(fileName.c_str(), mode) )
218     {
219     cmSystemTools::SetPermissions(fileName.c_str(),
220 #if defined( _MSC_VER ) || defined( __MINGW32__ )
221       mode | S_IWRITE
222 #elif defined( __BORLANDC__ )
223       mode | S_IWUSR
224 #else
225       mode | S_IWUSR | S_IWGRP
226 #endif
227     );
228     }
229   // If GetPermissions fails, pretend like it is ok. File open will fail if
230   // the file is not writable
231   std::ofstream file(fileName.c_str(), append?std::ios::app: std::ios::out);
232   if ( !file )
233     {
234     std::string error = "Internal CMake error when trying to open file: ";
235     error += fileName.c_str();
236     error += " for writing.";
237     this->SetError(error.c_str());
238     return false;
239     }
240   file << message;
241   file.close();
242   if(mode)
243     {
244     cmSystemTools::SetPermissions(fileName.c_str(), mode);
245     }
246   return true;
247 }
248
249 //----------------------------------------------------------------------------
250 bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args)
251 {
252   if ( args.size() < 3 )
253     {
254     this->SetError("READ must be called with at least two additional "
255                    "arguments");
256     return false;
257     }
258
259   cmCommandArgumentsHelper argHelper;
260   cmCommandArgumentGroup group;
261
262   cmCAString readArg    (&argHelper, "READ");
263   cmCAString fileNameArg    (&argHelper, 0);
264   cmCAString resultArg      (&argHelper, 0);
265
266   cmCAString offsetArg      (&argHelper, "OFFSET", &group);
267   cmCAString limitArg       (&argHelper, "LIMIT", &group);
268   cmCAEnabler hexOutputArg  (&argHelper, "HEX", &group);
269   readArg.Follows(0);
270   fileNameArg.Follows(&readArg);
271   resultArg.Follows(&fileNameArg);
272   group.Follows(&resultArg);
273   argHelper.Parse(&args, 0);
274
275   std::string fileName = fileNameArg.GetString();
276   if ( !cmsys::SystemTools::FileIsFullPath(fileName.c_str()) )
277     {
278     fileName = this->Makefile->GetCurrentDirectory();
279     fileName += "/" + fileNameArg.GetString();
280     }
281
282   std::string variable = resultArg.GetString();
283
284   // Open the specified file.
285 #if defined(_WIN32) || defined(__CYGWIN__)
286   std::ifstream file(fileName.c_str(), std::ios::in |
287                (hexOutputArg.IsEnabled() ? std::ios::binary : std::ios::in));
288 #else
289   std::ifstream file(fileName.c_str(), std::ios::in);
290 #endif
291
292   if ( !file )
293     {
294     std::string error = "Internal CMake error when trying to open file: ";
295     error += fileName.c_str();
296     error += " for reading.";
297     this->SetError(error.c_str());
298     return false;
299     }
300
301   // is there a limit?
302   long sizeLimit = -1;
303   if (limitArg.GetString().size() > 0)
304     {
305     sizeLimit = atoi(limitArg.GetCString());
306     }
307
308   // is there an offset?
309   long offset = 0;
310   if (offsetArg.GetString().size() > 0)
311     {
312     offset = atoi(offsetArg.GetCString());
313     }
314
315   file.seekg(offset, std::ios::beg); // explicit ios::beg for IBM VisualAge 6
316
317   std::string output;
318
319   if (hexOutputArg.IsEnabled())
320     {
321     // Convert part of the file into hex code
322     char c;
323     while((sizeLimit != 0) && (file.get(c)))
324       {
325       char hex[4];
326       sprintf(hex, "%.2x", c&0xff);
327       output += hex;
328       if (sizeLimit > 0)
329         {
330         sizeLimit--;
331         }
332       }
333     }
334   else
335     {
336     std::string line;
337     bool has_newline = false;
338     while (sizeLimit != 0 &&
339           cmSystemTools::GetLineFromStream(file, line, &has_newline,
340                                             sizeLimit) )
341       {
342       if (sizeLimit > 0)
343         {
344         sizeLimit = sizeLimit - static_cast<long>(line.size());
345         if (has_newline)
346           {
347           sizeLimit--;
348           }
349         if (sizeLimit < 0)
350           {
351           sizeLimit = 0;
352           }
353         }
354       output += line;
355       if ( has_newline )
356         {
357         output += "\n";
358         }
359       }
360     }
361   this->Makefile->AddDefinition(variable.c_str(), output.c_str());
362   return true;
363 }
364
365 //----------------------------------------------------------------------------
366 bool cmFileCommand::HandleHashCommand(std::vector<std::string> const& args)
367 {
368 #if defined(CMAKE_BUILD_WITH_CMAKE)
369   if(args.size() != 3)
370     {
371     cmOStringStream e;
372     e << args[0] << " requires a file name and output variable";
373     this->SetError(e.str().c_str());
374     return false;
375     }
376
377   cmsys::auto_ptr<cmCryptoHash> hash(cmCryptoHash::New(args[0].c_str()));
378   if(hash.get())
379     {
380     std::string out = hash->HashFile(args[1].c_str());
381     if(!out.empty())
382       {
383       this->Makefile->AddDefinition(args[2].c_str(), out.c_str());
384       return true;
385       }
386     cmOStringStream e;
387     e << args[0] << " failed to read file \"" << args[1] << "\": "
388       << cmSystemTools::GetLastSystemError();
389     this->SetError(e.str().c_str());
390     }
391   return false;
392 #else
393   cmOStringStream e;
394   e << args[0] << " not available during bootstrap";
395   this->SetError(e.str().c_str());
396   return false;
397 #endif
398 }
399
400 //----------------------------------------------------------------------------
401 bool cmFileCommand::HandleStringsCommand(std::vector<std::string> const& args)
402 {
403   if(args.size() < 3)
404     {
405     this->SetError("STRINGS requires a file name and output variable");
406     return false;
407     }
408
409   // Get the file to read.
410   std::string fileName = args[1];
411   if(!cmsys::SystemTools::FileIsFullPath(fileName.c_str()))
412     {
413     fileName = this->Makefile->GetCurrentDirectory();
414     fileName += "/" + args[1];
415     }
416
417   // Get the variable in which to store the results.
418   std::string outVar = args[2];
419
420   // Parse the options.
421   enum { arg_none,
422          arg_limit_input,
423          arg_limit_output,
424          arg_limit_count,
425          arg_length_minimum,
426          arg_length_maximum,
427          arg__maximum,
428          arg_regex };
429   unsigned int minlen = 0;
430   unsigned int maxlen = 0;
431   int limit_input = -1;
432   int limit_output = -1;
433   unsigned int limit_count = 0;
434   cmsys::RegularExpression regex;
435   bool have_regex = false;
436   bool newline_consume = false;
437   bool hex_conversion_enabled = true;
438   int arg_mode = arg_none;
439   for(unsigned int i=3; i < args.size(); ++i)
440     {
441     if(args[i] == "LIMIT_INPUT")
442       {
443       arg_mode = arg_limit_input;
444       }
445     else if(args[i] == "LIMIT_OUTPUT")
446       {
447       arg_mode = arg_limit_output;
448       }
449     else if(args[i] == "LIMIT_COUNT")
450       {
451       arg_mode = arg_limit_count;
452       }
453     else if(args[i] == "LENGTH_MINIMUM")
454       {
455       arg_mode = arg_length_minimum;
456       }
457     else if(args[i] == "LENGTH_MAXIMUM")
458       {
459       arg_mode = arg_length_maximum;
460       }
461     else if(args[i] == "REGEX")
462       {
463       arg_mode = arg_regex;
464       }
465     else if(args[i] == "NEWLINE_CONSUME")
466       {
467       newline_consume = true;
468       arg_mode = arg_none;
469       }
470     else if(args[i] == "NO_HEX_CONVERSION")
471       {
472       hex_conversion_enabled = false;
473       arg_mode = arg_none;
474       }
475     else if(arg_mode == arg_limit_input)
476       {
477       if(sscanf(args[i].c_str(), "%d", &limit_input) != 1 ||
478          limit_input < 0)
479         {
480         cmOStringStream e;
481         e << "STRINGS option LIMIT_INPUT value \""
482           << args[i] << "\" is not an unsigned integer.";
483         this->SetError(e.str().c_str());
484         return false;
485         }
486       arg_mode = arg_none;
487       }
488     else if(arg_mode == arg_limit_output)
489       {
490       if(sscanf(args[i].c_str(), "%d", &limit_output) != 1 ||
491          limit_output < 0)
492         {
493         cmOStringStream e;
494         e << "STRINGS option LIMIT_OUTPUT value \""
495           << args[i] << "\" is not an unsigned integer.";
496         this->SetError(e.str().c_str());
497         return false;
498         }
499       arg_mode = arg_none;
500       }
501     else if(arg_mode == arg_limit_count)
502       {
503       int count;
504       if(sscanf(args[i].c_str(), "%d", &count) != 1 || count < 0)
505         {
506         cmOStringStream e;
507         e << "STRINGS option LIMIT_COUNT value \""
508           << args[i] << "\" is not an unsigned integer.";
509         this->SetError(e.str().c_str());
510         return false;
511         }
512       limit_count = count;
513       arg_mode = arg_none;
514       }
515     else if(arg_mode == arg_length_minimum)
516       {
517       int len;
518       if(sscanf(args[i].c_str(), "%d", &len) != 1 || len < 0)
519         {
520         cmOStringStream e;
521         e << "STRINGS option LENGTH_MINIMUM value \""
522           << args[i] << "\" is not an unsigned integer.";
523         this->SetError(e.str().c_str());
524         return false;
525         }
526       minlen = len;
527       arg_mode = arg_none;
528       }
529     else if(arg_mode == arg_length_maximum)
530       {
531       int len;
532       if(sscanf(args[i].c_str(), "%d", &len) != 1 || len < 0)
533         {
534         cmOStringStream e;
535         e << "STRINGS option LENGTH_MAXIMUM value \""
536           << args[i] << "\" is not an unsigned integer.";
537         this->SetError(e.str().c_str());
538         return false;
539         }
540       maxlen = len;
541       arg_mode = arg_none;
542       }
543     else if(arg_mode == arg_regex)
544       {
545       if(!regex.compile(args[i].c_str()))
546         {
547         cmOStringStream e;
548         e << "STRINGS option REGEX value \""
549           << args[i] << "\" could not be compiled.";
550         this->SetError(e.str().c_str());
551         return false;
552         }
553       have_regex = true;
554       arg_mode = arg_none;
555       }
556     else
557       {
558       cmOStringStream e;
559       e << "STRINGS given unknown argument \""
560         << args[i] << "\"";
561       this->SetError(e.str().c_str());
562       return false;
563       }
564     }
565
566   if (hex_conversion_enabled)
567     {
568     // TODO: should work without temp file, but just on a memory buffer
569     std::string binaryFileName = this->Makefile->GetCurrentOutputDirectory();
570     binaryFileName += cmake::GetCMakeFilesDirectory();
571     binaryFileName += "/FileCommandStringsBinaryFile";
572     if(cmHexFileConverter::TryConvert(fileName.c_str(),binaryFileName.c_str()))
573       {
574       fileName = binaryFileName;
575       }
576     }
577
578   // Open the specified file.
579 #if defined(_WIN32) || defined(__CYGWIN__)
580   std::ifstream fin(fileName.c_str(), std::ios::in | std::ios::binary);
581 #else
582   std::ifstream fin(fileName.c_str(), std::ios::in);
583 #endif
584   if(!fin)
585     {
586     cmOStringStream e;
587     e << "STRINGS file \"" << fileName << "\" cannot be read.";
588     this->SetError(e.str().c_str());
589     return false;
590     }
591
592   // Parse strings out of the file.
593   int output_size = 0;
594   std::vector<std::string> strings;
595   std::string s;
596   int c;
597   while((!limit_count || strings.size() < limit_count) &&
598         (limit_input < 0 || static_cast<int>(fin.tellg()) < limit_input) &&
599         (c = fin.get(), fin))
600     {
601     if(c == '\n' && !newline_consume)
602       {
603       // The current line has been terminated.  Check if the current
604       // string matches the requirements.  The length may now be as
605       // low as zero since blank lines are allowed.
606       if(s.length() >= minlen &&
607          (!have_regex || regex.find(s.c_str())))
608         {
609         output_size += static_cast<int>(s.size()) + 1;
610         if(limit_output >= 0 && output_size >= limit_output)
611           {
612           s = "";
613           break;
614           }
615         strings.push_back(s);
616         }
617
618       // Reset the string to empty.
619       s = "";
620       }
621     else if(c == '\r')
622       {
623       // Ignore CR character to make output always have UNIX newlines.
624       }
625     else if((c >= 0x20 && c < 0x7F) || c == '\t' ||
626             (c == '\n' && newline_consume))
627       {
628       // This is an ASCII character that may be part of a string.
629       // Cast added to avoid compiler warning. Cast is ok because
630       // c is guaranteed to fit in char by the above if...
631       s += static_cast<char>(c);
632       }
633     else
634       {
635       // TODO: Support ENCODING option.  See issue #10519.
636       // A non-string character has been found.  Check if the current
637       // string matches the requirements.  We require that the length
638       // be at least one no matter what the user specified.
639       if(s.length() >= minlen && s.length() >= 1 &&
640          (!have_regex || regex.find(s.c_str())))
641         {
642         output_size += static_cast<int>(s.size()) + 1;
643         if(limit_output >= 0 && output_size >= limit_output)
644           {
645           s = "";
646           break;
647           }
648         strings.push_back(s);
649         }
650
651       // Reset the string to empty.
652       s = "";
653       }
654
655     // Terminate a string if the maximum length is reached.
656     if(maxlen > 0 && s.size() == maxlen)
657       {
658       if(s.length() >= minlen &&
659          (!have_regex || regex.find(s.c_str())))
660         {
661         output_size += static_cast<int>(s.size()) + 1;
662         if(limit_output >= 0 && output_size >= limit_output)
663           {
664           s = "";
665           break;
666           }
667         strings.push_back(s);
668         }
669       s = "";
670       }
671     }
672
673   // If there is a non-empty current string we have hit the end of the
674   // input file or the input size limit.  Check if the current string
675   // matches the requirements.
676   if((!limit_count || strings.size() < limit_count) &&
677      !s.empty() && s.length() >= minlen &&
678      (!have_regex || regex.find(s.c_str())))
679     {
680     output_size += static_cast<int>(s.size()) + 1;
681     if(limit_output < 0 || output_size < limit_output)
682       {
683       strings.push_back(s);
684       }
685     }
686
687   // Encode the result in a CMake list.
688   const char* sep = "";
689   std::string output;
690   for(std::vector<std::string>::const_iterator si = strings.begin();
691       si != strings.end(); ++si)
692     {
693     // Separate the strings in the output to make it a list.
694     output += sep;
695     sep = ";";
696
697     // Store the string in the output, but escape semicolons to
698     // make sure it is a list.
699     std::string const& sr = *si;
700     for(unsigned int i=0; i < sr.size(); ++i)
701       {
702       if(sr[i] == ';')
703         {
704         output += '\\';
705         }
706       output += sr[i];
707       }
708     }
709
710   // Save the output in a makefile variable.
711   this->Makefile->AddDefinition(outVar.c_str(), output.c_str());
712   return true;
713 }
714
715 //----------------------------------------------------------------------------
716 bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
717   bool recurse)
718 {
719   // File commands has at least one argument
720   assert(args.size() > 1);
721
722   std::vector<std::string>::const_iterator i = args.begin();
723
724   i++; // Get rid of subcommand
725
726   std::string variable = *i;
727   i++;
728   cmsys::Glob g;
729   g.SetRecurse(recurse);
730
731   bool explicitFollowSymlinks = false;
732   cmPolicies::PolicyStatus status =
733     this->Makefile->GetPolicyStatus(cmPolicies::CMP0009);
734   if(recurse)
735     {
736     switch(status)
737       {
738       case cmPolicies::NEW:
739         g.RecurseThroughSymlinksOff();
740         break;
741       case cmPolicies::OLD:
742       case cmPolicies::WARN:
743       case cmPolicies::REQUIRED_IF_USED:
744       case cmPolicies::REQUIRED_ALWAYS:
745         g.RecurseThroughSymlinksOn();
746         break;
747       }
748     }
749
750   std::string output = "";
751   bool first = true;
752   for ( ; i != args.end(); ++i )
753     {
754     if ( recurse && (*i == "FOLLOW_SYMLINKS") )
755       {
756       explicitFollowSymlinks = true;
757       g.RecurseThroughSymlinksOn();
758       ++i;
759       if ( i == args.end() )
760         {
761         this->SetError(
762           "GLOB_RECURSE requires a glob expression after FOLLOW_SYMLINKS");
763         return false;
764         }
765       }
766
767     if ( *i == "RELATIVE" )
768       {
769       ++i; // skip RELATIVE
770       if ( i == args.end() )
771         {
772         this->SetError("GLOB requires a directory after the RELATIVE tag");
773         return false;
774         }
775       g.SetRelative(i->c_str());
776       ++i;
777       if(i == args.end())
778         {
779         this->SetError("GLOB requires a glob expression after the directory");
780         return false;
781         }
782       }
783
784     if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
785       {
786       std::string expr = this->Makefile->GetCurrentDirectory();
787       // Handle script mode
788       if ( expr.size() > 0 )
789         {
790         expr += "/" + *i;
791         g.FindFiles(expr);
792         }
793       else
794         {
795         g.FindFiles(*i);
796         }
797       }
798     else
799       {
800       g.FindFiles(*i);
801       }
802
803     std::vector<std::string>::size_type cc;
804     std::vector<std::string>& files = g.GetFiles();
805     for ( cc = 0; cc < files.size(); cc ++ )
806       {
807       if ( !first )
808         {
809         output += ";";
810         }
811       output += files[cc];
812       first = false;
813       }
814     }
815
816   if(recurse && !explicitFollowSymlinks)
817     {
818     switch (status)
819       {
820       case cmPolicies::NEW:
821         // Correct behavior, yay!
822         break;
823       case cmPolicies::OLD:
824         // Probably not really the expected behavior, but the author explicitly
825         // asked for the old behavior... no warning.
826       case cmPolicies::WARN:
827         // Possibly unexpected old behavior *and* we actually traversed
828         // symlinks without being explicitly asked to: warn the author.
829         if(g.GetFollowedSymlinkCount() != 0)
830           {
831           this->Makefile->IssueMessage(cmake::AUTHOR_WARNING,
832             this->Makefile->GetPolicies()->
833               GetPolicyWarning(cmPolicies::CMP0009));
834           }
835         break;
836       case cmPolicies::REQUIRED_IF_USED:
837       case cmPolicies::REQUIRED_ALWAYS:
838         this->SetError("policy CMP0009 error");
839         this->Makefile->IssueMessage(cmake::FATAL_ERROR,
840           this->Makefile->GetPolicies()->
841             GetRequiredPolicyError(cmPolicies::CMP0009));
842         return false;
843       }
844     }
845
846   this->Makefile->AddDefinition(variable.c_str(), output.c_str());
847   return true;
848 }
849
850 //----------------------------------------------------------------------------
851 bool cmFileCommand::HandleMakeDirectoryCommand(
852   std::vector<std::string> const& args)
853 {
854   // File command has at least one argument
855   assert(args.size() > 1);
856
857   std::vector<std::string>::const_iterator i = args.begin();
858
859   i++; // Get rid of subcommand
860
861   std::string expr;
862   for ( ; i != args.end(); ++i )
863     {
864     const std::string* cdir = &(*i);
865     if ( !cmsys::SystemTools::FileIsFullPath(i->c_str()) )
866       {
867       expr = this->Makefile->GetCurrentDirectory();
868       expr += "/" + *i;
869       cdir = &expr;
870       }
871     if ( !this->Makefile->CanIWriteThisFile(cdir->c_str()) )
872       {
873       std::string e = "attempted to create a directory: " + *cdir
874         + " into a source directory.";
875       this->SetError(e.c_str());
876       cmSystemTools::SetFatalErrorOccured();
877       return false;
878       }
879     if ( !cmSystemTools::MakeDirectory(cdir->c_str()) )
880       {
881       std::string error = "problem creating directory: " + *cdir;
882       this->SetError(error.c_str());
883       return false;
884       }
885     }
886   return true;
887 }
888
889 //----------------------------------------------------------------------------
890 bool
891 cmFileCommand::HandleDifferentCommand(std::vector<std::string> const& args)
892 {
893   /*
894     FILE(DIFFERENT <variable> FILES <lhs> <rhs>)
895    */
896
897   // Evaluate arguments.
898   const char* file_lhs = 0;
899   const char* file_rhs = 0;
900   const char* var = 0;
901   enum Doing { DoingNone, DoingVar, DoingFileLHS, DoingFileRHS };
902   Doing doing = DoingVar;
903   for(unsigned int i=1; i < args.size(); ++i)
904     {
905     if(args[i] == "FILES")
906       {
907       doing = DoingFileLHS;
908       }
909     else if(doing == DoingVar)
910       {
911       var = args[i].c_str();
912       doing = DoingNone;
913       }
914     else if(doing == DoingFileLHS)
915       {
916       file_lhs = args[i].c_str();
917       doing = DoingFileRHS;
918       }
919     else if(doing == DoingFileRHS)
920       {
921       file_rhs = args[i].c_str();
922       doing = DoingNone;
923       }
924     else
925       {
926       cmOStringStream e;
927       e << "DIFFERENT given unknown argument " << args[i];
928       this->SetError(e.str().c_str());
929       return false;
930       }
931     }
932   if(!var)
933     {
934     this->SetError("DIFFERENT not given result variable name.");
935     return false;
936     }
937   if(!file_lhs || !file_rhs)
938     {
939     this->SetError("DIFFERENT not given FILES option with two file names.");
940     return false;
941     }
942
943   // Compare the files.
944   const char* result =
945     cmSystemTools::FilesDiffer(file_lhs, file_rhs)? "1" : "0";
946   this->Makefile->AddDefinition(var, result);
947   return true;
948 }
949
950 //----------------------------------------------------------------------------
951 // File installation helper class.
952 struct cmFileCopier
953 {
954   cmFileCopier(cmFileCommand* command, const char* name = "COPY"):
955     FileCommand(command),
956     Makefile(command->GetMakefile()),
957     Name(name),
958     Always(false),
959     MatchlessFiles(true),
960     FilePermissions(0),
961     DirPermissions(0),
962     CurrentMatchRule(0),
963     UseGivenPermissionsFile(false),
964     UseGivenPermissionsDir(false),
965     UseSourcePermissions(true),
966     Doing(DoingNone)
967     {
968     }
969   virtual ~cmFileCopier() {}
970
971   bool Run(std::vector<std::string> const& args);
972 protected:
973
974   cmFileCommand* FileCommand;
975   cmMakefile* Makefile;
976   const char* Name;
977   bool Always;
978   cmFileTimeComparison FileTimes;
979
980   // Whether to install a file not matching any expression.
981   bool MatchlessFiles;
982
983   // Permissions for files and directories installed by this object.
984   mode_t FilePermissions;
985   mode_t DirPermissions;
986
987   // Properties set by pattern and regex match rules.
988   struct MatchProperties
989   {
990     bool Exclude;
991     mode_t Permissions;
992     MatchProperties(): Exclude(false), Permissions(0) {}
993   };
994   struct MatchRule;
995   friend struct MatchRule;
996   struct MatchRule
997   {
998     cmsys::RegularExpression Regex;
999     MatchProperties Properties;
1000     std::string RegexString;
1001     MatchRule(std::string const& regex):
1002       Regex(regex.c_str()), RegexString(regex) {}
1003   };
1004   std::vector<MatchRule> MatchRules;
1005
1006   // Get the properties from rules matching this input file.
1007   MatchProperties CollectMatchProperties(const char* file)
1008     {
1009     // Match rules are case-insensitive on some platforms.
1010 #if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
1011     std::string lower = cmSystemTools::LowerCase(file);
1012     const char* file_to_match = lower.c_str();
1013 #else
1014     const char* file_to_match = file;
1015 #endif
1016
1017     // Collect properties from all matching rules.
1018     bool matched = false;
1019     MatchProperties result;
1020     for(std::vector<MatchRule>::iterator mr = this->MatchRules.begin();
1021         mr != this->MatchRules.end(); ++mr)
1022       {
1023       if(mr->Regex.find(file_to_match))
1024         {
1025         matched = true;
1026         result.Exclude |= mr->Properties.Exclude;
1027         result.Permissions |= mr->Properties.Permissions;
1028         }
1029       }
1030     if(!matched && !this->MatchlessFiles)
1031       {
1032       result.Exclude = !cmSystemTools::FileIsDirectory(file);
1033       }
1034     return result;
1035     }
1036
1037   bool SetPermissions(const char* toFile, mode_t permissions)
1038     {
1039     if(permissions && !cmSystemTools::SetPermissions(toFile, permissions))
1040       {
1041       cmOStringStream e;
1042       e << this->Name << " cannot set permissions on \"" << toFile << "\"";
1043       this->FileCommand->SetError(e.str().c_str());
1044       return false;
1045       }
1046     return true;
1047     }
1048
1049   // Translate an argument to a permissions bit.
1050   bool CheckPermissions(std::string const& arg, mode_t& permissions)
1051     {
1052     if(arg == "OWNER_READ")         { permissions |= mode_owner_read; }
1053     else if(arg == "OWNER_WRITE")   { permissions |= mode_owner_write; }
1054     else if(arg == "OWNER_EXECUTE") { permissions |= mode_owner_execute; }
1055     else if(arg == "GROUP_READ")    { permissions |= mode_group_read; }
1056     else if(arg == "GROUP_WRITE")   { permissions |= mode_group_write; }
1057     else if(arg == "GROUP_EXECUTE") { permissions |= mode_group_execute; }
1058     else if(arg == "WORLD_READ")    { permissions |= mode_world_read; }
1059     else if(arg == "WORLD_WRITE")   { permissions |= mode_world_write; }
1060     else if(arg == "WORLD_EXECUTE") { permissions |= mode_world_execute; }
1061     else if(arg == "SETUID")        { permissions |= mode_setuid; }
1062     else if(arg == "SETGID")        { permissions |= mode_setgid; }
1063     else
1064       {
1065       cmOStringStream e;
1066       e << this->Name << " given invalid permission \"" << arg << "\".";
1067       this->FileCommand->SetError(e.str().c_str());
1068       return false;
1069       }
1070     return true;
1071     }
1072
1073   bool InstallSymlink(const char* fromFile, const char* toFile);
1074   bool InstallFile(const char* fromFile, const char* toFile,
1075                    MatchProperties const& match_properties);
1076   bool InstallDirectory(const char* source, const char* destination,
1077                         MatchProperties const& match_properties);
1078   virtual bool Install(const char* fromFile, const char* toFile);
1079   virtual std::string const& ToName(std::string const& fromName)
1080     { return fromName; }
1081
1082   enum Type
1083   {
1084     TypeFile,
1085     TypeDir,
1086     TypeLink
1087   };
1088   virtual void ReportCopy(const char*, Type, bool) {}
1089   virtual bool ReportMissing(const char* fromFile)
1090     {
1091     // The input file does not exist and installation is not optional.
1092     cmOStringStream e;
1093     e << this->Name << " cannot find \"" << fromFile << "\".";
1094     this->FileCommand->SetError(e.str().c_str());
1095     return false;
1096     }
1097
1098   MatchRule* CurrentMatchRule;
1099   bool UseGivenPermissionsFile;
1100   bool UseGivenPermissionsDir;
1101   bool UseSourcePermissions;
1102   std::string Destination;
1103   std::vector<std::string> Files;
1104   int Doing;
1105
1106   virtual bool Parse(std::vector<std::string> const& args);
1107   enum
1108   {
1109     DoingNone,
1110     DoingError,
1111     DoingDestination,
1112     DoingFiles,
1113     DoingPattern,
1114     DoingRegex,
1115     DoingPermissionsFile,
1116     DoingPermissionsDir,
1117     DoingPermissionsMatch,
1118     DoingLast1
1119   };
1120   virtual bool CheckKeyword(std::string const& arg);
1121   virtual bool CheckValue(std::string const& arg);
1122
1123   void NotBeforeMatch(std::string const& arg)
1124     {
1125     cmOStringStream e;
1126     e << "option " << arg << " may not appear before PATTERN or REGEX.";
1127     this->FileCommand->SetError(e.str().c_str());
1128     this->Doing = DoingError;
1129     }
1130   void NotAfterMatch(std::string const& arg)
1131     {
1132     cmOStringStream e;
1133     e << "option " << arg << " may not appear after PATTERN or REGEX.";
1134     this->FileCommand->SetError(e.str().c_str());
1135     this->Doing = DoingError;
1136     }
1137   virtual void DefaultFilePermissions()
1138     {
1139     // Use read/write permissions.
1140     this->FilePermissions = 0;
1141     this->FilePermissions |= mode_owner_read;
1142     this->FilePermissions |= mode_owner_write;
1143     this->FilePermissions |= mode_group_read;
1144     this->FilePermissions |= mode_world_read;
1145     }
1146   virtual void DefaultDirectoryPermissions()
1147     {
1148     // Use read/write/executable permissions.
1149     this->DirPermissions = 0;
1150     this->DirPermissions |= mode_owner_read;
1151     this->DirPermissions |= mode_owner_write;
1152     this->DirPermissions |= mode_owner_execute;
1153     this->DirPermissions |= mode_group_read;
1154     this->DirPermissions |= mode_group_execute;
1155     this->DirPermissions |= mode_world_read;
1156     this->DirPermissions |= mode_world_execute;
1157     }
1158 };
1159
1160 //----------------------------------------------------------------------------
1161 bool cmFileCopier::Parse(std::vector<std::string> const& args)
1162 {
1163   this->Doing = DoingFiles;
1164   for(unsigned int i=1; i < args.size(); ++i)
1165     {
1166     // Check this argument.
1167     if(!this->CheckKeyword(args[i]) &&
1168        !this->CheckValue(args[i]))
1169       {
1170       cmOStringStream e;
1171       e << "called with unknown argument \"" << args[i] << "\".";
1172       this->FileCommand->SetError(e.str().c_str());
1173       return false;
1174       }
1175
1176     // Quit if an argument is invalid.
1177     if(this->Doing == DoingError)
1178       {
1179       return false;
1180       }
1181     }
1182
1183   // Require a destination.
1184   if(this->Destination.empty())
1185     {
1186     cmOStringStream e;
1187     e << this->Name << " given no DESTINATION";
1188     this->FileCommand->SetError(e.str().c_str());
1189     return false;
1190     }
1191
1192   // If file permissions were not specified set default permissions.
1193   if(!this->UseGivenPermissionsFile && !this->UseSourcePermissions)
1194     {
1195     this->DefaultFilePermissions();
1196     }
1197
1198   // If directory permissions were not specified set default permissions.
1199   if(!this->UseGivenPermissionsDir && !this->UseSourcePermissions)
1200     {
1201     this->DefaultDirectoryPermissions();
1202     }
1203
1204   return true;
1205 }
1206
1207 //----------------------------------------------------------------------------
1208 bool cmFileCopier::CheckKeyword(std::string const& arg)
1209 {
1210   if(arg == "DESTINATION")
1211     {
1212     if(this->CurrentMatchRule)
1213       {
1214       this->NotAfterMatch(arg);
1215       }
1216     else
1217       {
1218       this->Doing = DoingDestination;
1219       }
1220     }
1221   else if(arg == "PATTERN")
1222     {
1223     this->Doing = DoingPattern;
1224     }
1225   else if(arg == "REGEX")
1226     {
1227     this->Doing = DoingRegex;
1228     }
1229   else if(arg == "EXCLUDE")
1230     {
1231     // Add this property to the current match rule.
1232     if(this->CurrentMatchRule)
1233       {
1234       this->CurrentMatchRule->Properties.Exclude = true;
1235       this->Doing = DoingNone;
1236       }
1237     else
1238       {
1239       this->NotBeforeMatch(arg);
1240       }
1241     }
1242   else if(arg == "PERMISSIONS")
1243     {
1244     if(this->CurrentMatchRule)
1245       {
1246       this->Doing = DoingPermissionsMatch;
1247       }
1248     else
1249       {
1250       this->NotBeforeMatch(arg);
1251       }
1252     }
1253   else if(arg == "FILE_PERMISSIONS")
1254     {
1255     if(this->CurrentMatchRule)
1256       {
1257       this->NotAfterMatch(arg);
1258       }
1259     else
1260       {
1261       this->Doing = DoingPermissionsFile;
1262       this->UseGivenPermissionsFile = true;
1263       }
1264     }
1265   else if(arg == "DIRECTORY_PERMISSIONS")
1266     {
1267     if(this->CurrentMatchRule)
1268       {
1269       this->NotAfterMatch(arg);
1270       }
1271     else
1272       {
1273       this->Doing = DoingPermissionsDir;
1274       this->UseGivenPermissionsDir = true;
1275       }
1276     }
1277   else if(arg == "USE_SOURCE_PERMISSIONS")
1278     {
1279     if(this->CurrentMatchRule)
1280       {
1281       this->NotAfterMatch(arg);
1282       }
1283     else
1284       {
1285       this->Doing = DoingNone;
1286       this->UseSourcePermissions = true;
1287       }
1288     }
1289   else if(arg == "NO_SOURCE_PERMISSIONS")
1290     {
1291     if(this->CurrentMatchRule)
1292       {
1293       this->NotAfterMatch(arg);
1294       }
1295     else
1296       {
1297       this->Doing = DoingNone;
1298       this->UseSourcePermissions = false;
1299       }
1300     }
1301   else if(arg == "FILES_MATCHING")
1302     {
1303     if(this->CurrentMatchRule)
1304       {
1305       this->NotAfterMatch(arg);
1306       }
1307     else
1308       {
1309       this->Doing = DoingNone;
1310       this->MatchlessFiles = false;
1311       }
1312     }
1313   else
1314     {
1315     return false;
1316     }
1317   return true;
1318 }
1319
1320 //----------------------------------------------------------------------------
1321 bool cmFileCopier::CheckValue(std::string const& arg)
1322 {
1323   switch(this->Doing)
1324     {
1325     case DoingFiles:
1326       if(arg.empty() || cmSystemTools::FileIsFullPath(arg.c_str()))
1327         {
1328         this->Files.push_back(arg);
1329         }
1330       else
1331         {
1332         std::string file = this->Makefile->GetCurrentDirectory();
1333         file += "/" + arg;
1334         this->Files.push_back(file);
1335         }
1336       break;
1337     case DoingDestination:
1338       if(arg.empty() || cmSystemTools::FileIsFullPath(arg.c_str()))
1339         {
1340         this->Destination = arg;
1341         }
1342       else
1343         {
1344         this->Destination = this->Makefile->GetCurrentOutputDirectory();
1345         this->Destination += "/" + arg;
1346         }
1347       this->Doing = DoingNone;
1348       break;
1349     case DoingPattern:
1350       {
1351       // Convert the pattern to a regular expression.  Require a
1352       // leading slash and trailing end-of-string in the matched
1353       // string to make sure the pattern matches only whole file
1354       // names.
1355       std::string regex = "/";
1356       regex += cmsys::Glob::PatternToRegex(arg, false);
1357       regex += "$";
1358       this->MatchRules.push_back(MatchRule(regex));
1359       this->CurrentMatchRule = &*(this->MatchRules.end()-1);
1360       if(this->CurrentMatchRule->Regex.is_valid())
1361         {
1362         this->Doing = DoingNone;
1363         }
1364       else
1365         {
1366         cmOStringStream e;
1367         e << "could not compile PATTERN \"" << arg << "\".";
1368         this->FileCommand->SetError(e.str().c_str());
1369         this->Doing = DoingError;
1370         }
1371       }
1372       break;
1373     case DoingRegex:
1374       this->MatchRules.push_back(MatchRule(arg));
1375       this->CurrentMatchRule = &*(this->MatchRules.end()-1);
1376       if(this->CurrentMatchRule->Regex.is_valid())
1377         {
1378         this->Doing = DoingNone;
1379         }
1380       else
1381         {
1382         cmOStringStream e;
1383         e << "could not compile REGEX \"" << arg << "\".";
1384         this->FileCommand->SetError(e.str().c_str());
1385         this->Doing = DoingError;
1386         }
1387       break;
1388     case DoingPermissionsFile:
1389       if(!this->CheckPermissions(arg, this->FilePermissions))
1390         {
1391         this->Doing = DoingError;
1392         }
1393       break;
1394     case DoingPermissionsDir:
1395       if(!this->CheckPermissions(arg, this->DirPermissions))
1396         {
1397         this->Doing = DoingError;
1398         }
1399       break;
1400     case DoingPermissionsMatch:
1401       if(!this->CheckPermissions(
1402            arg, this->CurrentMatchRule->Properties.Permissions))
1403         {
1404         this->Doing = DoingError;
1405         }
1406       break;
1407     default:
1408       return false;
1409     }
1410   return true;
1411 }
1412
1413 //----------------------------------------------------------------------------
1414 bool cmFileCopier::Run(std::vector<std::string> const& args)
1415 {
1416   if(!this->Parse(args))
1417     {
1418     return false;
1419     }
1420
1421   std::vector<std::string> const& files = this->Files;
1422   for(std::vector<std::string>::size_type i = 0; i < files.size(); ++i)
1423     {
1424     // Split the input file into its directory and name components.
1425     std::vector<std::string> fromPathComponents;
1426     cmSystemTools::SplitPath(files[i].c_str(), fromPathComponents);
1427     std::string fromName = *(fromPathComponents.end()-1);
1428     std::string fromDir = cmSystemTools::JoinPath(fromPathComponents.begin(),
1429                                                   fromPathComponents.end()-1);
1430
1431     // Compute the full path to the destination file.
1432     std::string toFile = this->Destination;
1433     std::string const& toName = this->ToName(fromName);
1434     if(!toName.empty())
1435       {
1436       toFile += "/";
1437       toFile += toName;
1438       }
1439
1440     // Construct the full path to the source file.  The file name may
1441     // have been changed above.
1442     std::string fromFile = fromDir;
1443     if(!fromName.empty())
1444       {
1445       fromFile += "/";
1446       fromFile += fromName;
1447       }
1448
1449     if(!this->Install(fromFile.c_str(), toFile.c_str()))
1450       {
1451       return false;
1452       }
1453     }
1454   return true;
1455 }
1456
1457 //----------------------------------------------------------------------------
1458 bool cmFileCopier::Install(const char* fromFile, const char* toFile)
1459 {
1460   if(!*fromFile)
1461     {
1462     cmOStringStream e;
1463     e << "INSTALL encountered an empty string input file name.";
1464     this->FileCommand->SetError(e.str().c_str());
1465     return false;
1466     }
1467
1468   // Collect any properties matching this file name.
1469   MatchProperties match_properties = this->CollectMatchProperties(fromFile);
1470
1471   // Skip the file if it is excluded.
1472   if(match_properties.Exclude)
1473     {
1474     return true;
1475     }
1476
1477   if(cmSystemTools::SameFile(fromFile, toFile))
1478     {
1479     return true;
1480     }
1481   else if(cmSystemTools::FileIsSymlink(fromFile))
1482     {
1483     return this->InstallSymlink(fromFile, toFile);
1484     }
1485   else if(cmSystemTools::FileIsDirectory(fromFile))
1486     {
1487     return this->InstallDirectory(fromFile, toFile, match_properties);
1488     }
1489   else if(cmSystemTools::FileExists(fromFile))
1490     {
1491     return this->InstallFile(fromFile, toFile, match_properties);
1492     }
1493   return this->ReportMissing(fromFile);
1494 }
1495
1496 //----------------------------------------------------------------------------
1497 bool cmFileCopier::InstallSymlink(const char* fromFile, const char* toFile)
1498 {
1499   // Read the original symlink.
1500   std::string symlinkTarget;
1501   if(!cmSystemTools::ReadSymlink(fromFile, symlinkTarget))
1502     {
1503     cmOStringStream e;
1504     e << this->Name << " cannot read symlink \"" << fromFile
1505       << "\" to duplicate at \"" << toFile << "\".";
1506     this->FileCommand->SetError(e.str().c_str());
1507     return false;
1508     }
1509
1510   // Compare the symlink value to that at the destination if not
1511   // always installing.
1512   bool copy = true;
1513   if(!this->Always)
1514     {
1515     std::string oldSymlinkTarget;
1516     if(cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget))
1517       {
1518       if(symlinkTarget == oldSymlinkTarget)
1519         {
1520         copy = false;
1521         }
1522       }
1523     }
1524
1525   // Inform the user about this file installation.
1526   this->ReportCopy(toFile, TypeLink, copy);
1527
1528   if(copy)
1529     {
1530     // Remove the destination file so we can always create the symlink.
1531     cmSystemTools::RemoveFile(toFile);
1532
1533     // Create the symlink.
1534     if(!cmSystemTools::CreateSymlink(symlinkTarget.c_str(), toFile))
1535       {
1536       cmOStringStream e;
1537       e << this->Name <<  " cannot duplicate symlink \"" << fromFile
1538         << "\" at \"" << toFile << "\".";
1539       this->FileCommand->SetError(e.str().c_str());
1540       return false;
1541       }
1542     }
1543
1544   return true;
1545 }
1546
1547 //----------------------------------------------------------------------------
1548 bool cmFileCopier::InstallFile(const char* fromFile, const char* toFile,
1549                                MatchProperties const& match_properties)
1550 {
1551   // Determine whether we will copy the file.
1552   bool copy = true;
1553   if(!this->Always)
1554     {
1555     // If both files exist with the same time do not copy.
1556     if(!this->FileTimes.FileTimesDiffer(fromFile, toFile))
1557       {
1558       copy = false;
1559       }
1560     }
1561
1562   // Inform the user about this file installation.
1563   this->ReportCopy(toFile, TypeFile, copy);
1564
1565   // Copy the file.
1566   if(copy && !cmSystemTools::CopyAFile(fromFile, toFile, true))
1567     {
1568     cmOStringStream e;
1569     e << this->Name << " cannot copy file \"" << fromFile
1570       << "\" to \"" << toFile << "\".";
1571     this->FileCommand->SetError(e.str().c_str());
1572     return false;
1573     }
1574
1575   // Set the file modification time of the destination file.
1576   if(copy && !this->Always)
1577     {
1578     // Add write permission so we can set the file time.
1579     // Permissions are set unconditionally below anyway.
1580     mode_t perm = 0;
1581     if(cmSystemTools::GetPermissions(toFile, perm))
1582       {
1583       cmSystemTools::SetPermissions(toFile, perm | mode_owner_write);
1584       }
1585     if (!cmSystemTools::CopyFileTime(fromFile, toFile))
1586       {
1587       cmOStringStream e;
1588       e << this->Name << " cannot set modification time on \""
1589         << toFile << "\"";
1590       this->FileCommand->SetError(e.str().c_str());
1591       return false;
1592       }
1593     }
1594
1595   // Set permissions of the destination file.
1596   mode_t permissions = (match_properties.Permissions?
1597                         match_properties.Permissions : this->FilePermissions);
1598   if(!permissions)
1599     {
1600     // No permissions were explicitly provided but the user requested
1601     // that the source file permissions be used.
1602     cmSystemTools::GetPermissions(fromFile, permissions);
1603     }
1604   return this->SetPermissions(toFile, permissions);
1605 }
1606
1607 //----------------------------------------------------------------------------
1608 bool cmFileCopier::InstallDirectory(const char* source,
1609                                     const char* destination,
1610                                     MatchProperties const& match_properties)
1611 {
1612   // Inform the user about this directory installation.
1613   this->ReportCopy(destination, TypeDir, true);
1614
1615   // Make sure the destination directory exists.
1616   if(!cmSystemTools::MakeDirectory(destination))
1617     {
1618     cmOStringStream e;
1619     e << this->Name << " cannot make directory \"" << destination << "\": "
1620       << cmSystemTools::GetLastSystemError();
1621     this->FileCommand->SetError(e.str().c_str());
1622     return false;
1623     }
1624
1625   // Compute the requested permissions for the destination directory.
1626   mode_t permissions = (match_properties.Permissions?
1627                         match_properties.Permissions : this->DirPermissions);
1628   if(!permissions)
1629     {
1630     // No permissions were explicitly provided but the user requested
1631     // that the source directory permissions be used.
1632     cmSystemTools::GetPermissions(source, permissions);
1633     }
1634
1635   // Compute the set of permissions required on this directory to
1636   // recursively install files and subdirectories safely.
1637   mode_t required_permissions =
1638     mode_owner_read | mode_owner_write | mode_owner_execute;
1639
1640   // If the required permissions are specified it is safe to set the
1641   // final permissions now.  Otherwise we must add the required
1642   // permissions temporarily during file installation.
1643   mode_t permissions_before = 0;
1644   mode_t permissions_after = 0;
1645   if((permissions & required_permissions) == required_permissions)
1646     {
1647     permissions_before = permissions;
1648     }
1649   else
1650     {
1651     permissions_before = permissions | required_permissions;
1652     permissions_after = permissions;
1653     }
1654
1655   // Set the required permissions of the destination directory.
1656   if(!this->SetPermissions(destination, permissions_before))
1657     {
1658     return false;
1659     }
1660
1661   // Load the directory contents to traverse it recursively.
1662   cmsys::Directory dir;
1663   if(source && *source)
1664     {
1665     dir.Load(source);
1666     }
1667   unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
1668   for(unsigned long fileNum = 0; fileNum < numFiles; ++fileNum)
1669     {
1670     if(!(strcmp(dir.GetFile(fileNum), ".") == 0 ||
1671          strcmp(dir.GetFile(fileNum), "..") == 0))
1672       {
1673       cmsys_stl::string fromPath = source;
1674       fromPath += "/";
1675       fromPath += dir.GetFile(fileNum);
1676       std::string toPath = destination;
1677       toPath += "/";
1678       toPath += dir.GetFile(fileNum);
1679       if(!this->Install(fromPath.c_str(), toPath.c_str()))
1680         {
1681         return false;
1682         }
1683       }
1684     }
1685
1686   // Set the requested permissions of the destination directory.
1687   return this->SetPermissions(destination, permissions_after);
1688 }
1689
1690 //----------------------------------------------------------------------------
1691 bool cmFileCommand::HandleCopyCommand(std::vector<std::string> const& args)
1692 {
1693   cmFileCopier copier(this);
1694   return copier.Run(args);
1695 }
1696
1697 //----------------------------------------------------------------------------
1698 struct cmFileInstaller: public cmFileCopier
1699 {
1700   cmFileInstaller(cmFileCommand* command):
1701     cmFileCopier(command, "INSTALL"),
1702     InstallType(cmInstallType_FILES),
1703     Optional(false),
1704     DestDirLength(0)
1705     {
1706     // Installation does not use source permissions by default.
1707     this->UseSourcePermissions = false;
1708     // Check whether to copy files always or only if they have changed.
1709     this->Always =
1710       cmSystemTools::IsOn(cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS"));
1711     // Get the current manifest.
1712     this->Manifest =
1713       this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
1714     }
1715   ~cmFileInstaller()
1716     {
1717     // Save the updated install manifest.
1718     this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
1719                                   this->Manifest.c_str());
1720     }
1721
1722 protected:
1723   cmInstallType InstallType;
1724   bool Optional;
1725   int DestDirLength;
1726   std::string Rename;
1727
1728   std::string Manifest;
1729   void ManifestAppend(std::string const& file)
1730     {
1731     this->Manifest += ";";
1732     this->Manifest += file.substr(this->DestDirLength);
1733     }
1734
1735   virtual std::string const& ToName(std::string const& fromName)
1736     { return this->Rename.empty()? fromName : this->Rename; }
1737
1738   virtual void ReportCopy(const char* toFile, Type type, bool copy)
1739     {
1740     std::string message = (copy? "Installing: " : "Up-to-date: ");
1741     message += toFile;
1742     this->Makefile->DisplayStatus(message.c_str(), -1);
1743     if(type != TypeDir)
1744       {
1745       // Add the file to the manifest.
1746       this->ManifestAppend(toFile);
1747       }
1748     }
1749   virtual bool ReportMissing(const char* fromFile)
1750     {
1751     return (this->Optional ||
1752             this->cmFileCopier::ReportMissing(fromFile));
1753     }
1754   virtual bool Install(const char* fromFile, const char* toFile)
1755     {
1756     // Support installing from empty source to make a directory.
1757     if(this->InstallType == cmInstallType_DIRECTORY && !*fromFile)
1758       {
1759       return this->InstallDirectory(fromFile, toFile, MatchProperties());
1760       }
1761     return this->cmFileCopier::Install(fromFile, toFile);
1762     }
1763
1764   virtual bool Parse(std::vector<std::string> const& args);
1765   enum
1766   {
1767     DoingType = DoingLast1,
1768     DoingRename,
1769     DoingLast2
1770   };
1771   virtual bool CheckKeyword(std::string const& arg);
1772   virtual bool CheckValue(std::string const& arg);
1773   virtual void DefaultFilePermissions()
1774     {
1775     this->cmFileCopier::DefaultFilePermissions();
1776     // Add execute permissions based on the target type.
1777     switch(this->InstallType)
1778       {
1779       case cmInstallType_SHARED_LIBRARY:
1780       case cmInstallType_MODULE_LIBRARY:
1781         if(this->Makefile->IsOn("CMAKE_INSTALL_SO_NO_EXE"))
1782           {
1783           break;
1784           }
1785       case cmInstallType_EXECUTABLE:
1786       case cmInstallType_PROGRAMS:
1787         this->FilePermissions |= mode_owner_execute;
1788         this->FilePermissions |= mode_group_execute;
1789         this->FilePermissions |= mode_world_execute;
1790         break;
1791       default: break;
1792       }
1793     }
1794   bool GetTargetTypeFromString(const std::string& stype);
1795   bool HandleInstallDestination();
1796 };
1797
1798 //----------------------------------------------------------------------------
1799 bool cmFileInstaller::Parse(std::vector<std::string> const& args)
1800 {
1801   if(!this->cmFileCopier::Parse(args))
1802     {
1803     return false;
1804     }
1805
1806   if(!this->Rename.empty())
1807     {
1808     if(this->InstallType != cmInstallType_FILES &&
1809        this->InstallType != cmInstallType_PROGRAMS)
1810       {
1811       this->FileCommand->SetError("INSTALL option RENAME may be used "
1812                                   "only with FILES or PROGRAMS.");
1813       return false;
1814       }
1815     if(this->Files.size() > 1)
1816       {
1817       this->FileCommand->SetError("INSTALL option RENAME may be used "
1818                                   "only with one file.");
1819       return false;
1820       }
1821     }
1822
1823   if(!this->HandleInstallDestination())
1824     {
1825     return false;
1826     }
1827
1828   return true;
1829 }
1830
1831 //----------------------------------------------------------------------------
1832 bool cmFileInstaller::CheckKeyword(std::string const& arg)
1833 {
1834   if(arg == "TYPE")
1835     {
1836     if(this->CurrentMatchRule)
1837       {
1838       this->NotAfterMatch(arg);
1839       }
1840     else
1841       {
1842       this->Doing = DoingType;
1843       }
1844     }
1845   else if(arg == "FILES")
1846     {
1847     if(this->CurrentMatchRule)
1848       {
1849       this->NotAfterMatch(arg);
1850       }
1851     else
1852       {
1853       this->Doing = DoingFiles;
1854       }
1855     }
1856   else if(arg == "RENAME")
1857     {
1858     if(this->CurrentMatchRule)
1859       {
1860       this->NotAfterMatch(arg);
1861       }
1862     else
1863       {
1864       this->Doing = DoingRename;
1865       }
1866     }
1867   else if(arg == "OPTIONAL")
1868     {
1869     if(this->CurrentMatchRule)
1870       {
1871       this->NotAfterMatch(arg);
1872       }
1873     else
1874       {
1875       this->Doing = DoingNone;
1876       this->Optional = true;
1877       }
1878     }
1879   else if(arg == "PERMISSIONS")
1880     {
1881     if(this->CurrentMatchRule)
1882       {
1883       this->Doing = DoingPermissionsMatch;
1884       }
1885     else
1886       {
1887       // file(INSTALL) aliases PERMISSIONS to FILE_PERMISSIONS
1888       this->Doing = DoingPermissionsFile;
1889       this->UseGivenPermissionsFile = true;
1890       }
1891     }
1892   else if(arg == "DIR_PERMISSIONS")
1893     {
1894     if(this->CurrentMatchRule)
1895       {
1896       this->NotAfterMatch(arg);
1897       }
1898     else
1899       {
1900       // file(INSTALL) aliases DIR_PERMISSIONS to DIRECTORY_PERMISSIONS
1901       this->Doing = DoingPermissionsDir;
1902       this->UseGivenPermissionsDir = true;
1903       }
1904     }
1905   else if(arg == "COMPONENTS" || arg == "CONFIGURATIONS" ||
1906           arg == "PROPERTIES")
1907     {
1908     cmOStringStream e;
1909     e << "INSTALL called with old-style " << arg << " argument.  "
1910       << "This script was generated with an older version of CMake.  "
1911       << "Re-run this cmake version on your build tree.";
1912     this->FileCommand->SetError(e.str().c_str());
1913     this->Doing = DoingError;
1914     }
1915   else
1916     {
1917     return this->cmFileCopier::CheckKeyword(arg);
1918     }
1919   return true;
1920 }
1921
1922 //----------------------------------------------------------------------------
1923 bool cmFileInstaller::CheckValue(std::string const& arg)
1924 {
1925   switch(this->Doing)
1926     {
1927     case DoingType:
1928       if(!this->GetTargetTypeFromString(arg))
1929         {
1930         this->Doing = DoingError;
1931         }
1932       break;
1933     case DoingRename:
1934       this->Rename = arg;
1935       break;
1936     default:
1937       return this->cmFileCopier::CheckValue(arg);
1938     }
1939   return true;
1940 }
1941
1942 //----------------------------------------------------------------------------
1943 bool cmFileInstaller
1944 ::GetTargetTypeFromString(const std::string& stype)
1945 {
1946   if ( stype == "EXECUTABLE" )
1947     {
1948     this->InstallType = cmInstallType_EXECUTABLE;
1949     }
1950   else if ( stype == "FILE" )
1951     {
1952     this->InstallType = cmInstallType_FILES;
1953     }
1954   else if ( stype == "PROGRAM" )
1955     {
1956     this->InstallType = cmInstallType_PROGRAMS;
1957     }
1958   else if ( stype == "STATIC_LIBRARY" )
1959     {
1960     this->InstallType = cmInstallType_STATIC_LIBRARY;
1961     }
1962   else if ( stype == "SHARED_LIBRARY" )
1963     {
1964     this->InstallType = cmInstallType_SHARED_LIBRARY;
1965     }
1966   else if ( stype == "MODULE" )
1967     {
1968     this->InstallType = cmInstallType_MODULE_LIBRARY;
1969     }
1970   else if ( stype == "DIRECTORY" )
1971     {
1972     this->InstallType = cmInstallType_DIRECTORY;
1973     }
1974   else
1975     {
1976     cmOStringStream e;
1977     e << "Option TYPE given unknown value \"" << stype << "\".";
1978     this->FileCommand->SetError(e.str().c_str());
1979     return false;
1980     }
1981   return true;
1982 }
1983
1984 //----------------------------------------------------------------------------
1985 bool cmFileInstaller::HandleInstallDestination()
1986 {
1987   std::string& destination = this->Destination;
1988
1989   // allow for / to be a valid destination
1990   if ( destination.size() < 2 && destination != "/" )
1991     {
1992     this->FileCommand->SetError("called with inappropriate arguments. "
1993         "No DESTINATION provided or .");
1994     return false;
1995     }
1996
1997   const char* destdir = cmSystemTools::GetEnv("DESTDIR");
1998   if ( destdir && *destdir )
1999     {
2000     std::string sdestdir = destdir;
2001     cmSystemTools::ConvertToUnixSlashes(sdestdir);
2002     char ch1 = destination[0];
2003     char ch2 = destination[1];
2004     char ch3 = 0;
2005     if ( destination.size() > 2 )
2006       {
2007       ch3 = destination[2];
2008       }
2009     int skip = 0;
2010     if ( ch1 != '/' )
2011       {
2012       int relative = 0;
2013       if (((ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z')) &&
2014              ch2 == ':' )
2015         {
2016         // Assume windows
2017         // let's do some destdir magic:
2018         skip = 2;
2019         if ( ch3 != '/' )
2020           {
2021           relative = 1;
2022           }
2023         }
2024       else
2025         {
2026         relative = 1;
2027         }
2028       if ( relative )
2029         {
2030         // This is relative path on unix or windows. Since we are doing
2031         // destdir, this case does not make sense.
2032         this->FileCommand->SetError(
2033           "called with relative DESTINATION. This "
2034           "does not make sense when using DESTDIR. Specify "
2035           "absolute path or remove DESTDIR environment variable.");
2036         return false;
2037         }
2038       }
2039     else
2040       {
2041       if ( ch2 == '/' )
2042         {
2043         // looks like a network path.
2044         std::string message = "called with network path DESTINATION. This "
2045           "does not make sense when using DESTDIR. Specify local "
2046           "absolute path or remove DESTDIR environment variable."
2047           "\nDESTINATION=\n";
2048         message += destination;
2049         this->FileCommand->SetError(message.c_str());
2050         return false;
2051         }
2052       }
2053     destination = sdestdir + (destination.c_str() + skip);
2054     this->DestDirLength = int(sdestdir.size());
2055     }
2056
2057   if ( !cmSystemTools::FileExists(destination.c_str()) )
2058     {
2059     if ( !cmSystemTools::MakeDirectory(destination.c_str()) )
2060       {
2061       std::string errstring = "cannot create directory: " + destination +
2062           ". Maybe need administrative privileges.";
2063       this->FileCommand->SetError(errstring.c_str());
2064       return false;
2065       }
2066     }
2067   if ( !cmSystemTools::FileIsDirectory(destination.c_str()) )
2068     {
2069     std::string errstring = "INSTALL destination: " + destination +
2070         " is not a directory.";
2071     this->FileCommand->SetError(errstring.c_str());
2072     return false;
2073     }
2074   return true;
2075 }
2076
2077 //----------------------------------------------------------------------------
2078 bool
2079 cmFileCommand::HandleRPathChangeCommand(std::vector<std::string> const& args)
2080 {
2081   // Evaluate arguments.
2082   const char* file = 0;
2083   const char* oldRPath = 0;
2084   const char* newRPath = 0;
2085   enum Doing { DoingNone, DoingFile, DoingOld, DoingNew };
2086   Doing doing = DoingNone;
2087   for(unsigned int i=1; i < args.size(); ++i)
2088     {
2089     if(args[i] == "OLD_RPATH")
2090       {
2091       doing = DoingOld;
2092       }
2093     else if(args[i] == "NEW_RPATH")
2094       {
2095       doing = DoingNew;
2096       }
2097     else if(args[i] == "FILE")
2098       {
2099       doing = DoingFile;
2100       }
2101     else if(doing == DoingFile)
2102       {
2103       file = args[i].c_str();
2104       doing = DoingNone;
2105       }
2106     else if(doing == DoingOld)
2107       {
2108       oldRPath = args[i].c_str();
2109       doing = DoingNone;
2110       }
2111     else if(doing == DoingNew)
2112       {
2113       newRPath = args[i].c_str();
2114       doing = DoingNone;
2115       }
2116     else
2117       {
2118       cmOStringStream e;
2119       e << "RPATH_CHANGE given unknown argument " << args[i];
2120       this->SetError(e.str().c_str());
2121       return false;
2122       }
2123     }
2124   if(!file)
2125     {
2126     this->SetError("RPATH_CHANGE not given FILE option.");
2127     return false;
2128     }
2129   if(!oldRPath)
2130     {
2131     this->SetError("RPATH_CHANGE not given OLD_RPATH option.");
2132     return false;
2133     }
2134   if(!newRPath)
2135     {
2136     this->SetError("RPATH_CHANGE not given NEW_RPATH option.");
2137     return false;
2138     }
2139   if(!cmSystemTools::FileExists(file, true))
2140     {
2141     cmOStringStream e;
2142     e << "RPATH_CHANGE given FILE \"" << file << "\" that does not exist.";
2143     this->SetError(e.str().c_str());
2144     return false;
2145     }
2146   bool success = true;
2147   cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
2148   bool have_ft = cmSystemTools::FileTimeGet(file, ft);
2149   std::string emsg;
2150   bool changed;
2151   if(!cmSystemTools::ChangeRPath(file, oldRPath, newRPath, &emsg, &changed))
2152     {
2153     cmOStringStream e;
2154     e << "RPATH_CHANGE could not write new RPATH:\n"
2155       << "  " << newRPath << "\n"
2156       << "to the file:\n"
2157       << "  " << file << "\n"
2158       << emsg;
2159     this->SetError(e.str().c_str());
2160     success = false;
2161     }
2162   if(success)
2163     {
2164     if(changed)
2165       {
2166       std::string message = "Set runtime path of \"";
2167       message += file;
2168       message += "\" to \"";
2169       message += newRPath;
2170       message += "\"";
2171       this->Makefile->DisplayStatus(message.c_str(), -1);
2172       }
2173     if(have_ft)
2174       {
2175       cmSystemTools::FileTimeSet(file, ft);
2176       }
2177     }
2178   cmSystemTools::FileTimeDelete(ft);
2179   return success;
2180 }
2181
2182 //----------------------------------------------------------------------------
2183 bool
2184 cmFileCommand::HandleRPathRemoveCommand(std::vector<std::string> const& args)
2185 {
2186   // Evaluate arguments.
2187   const char* file = 0;
2188   enum Doing { DoingNone, DoingFile };
2189   Doing doing = DoingNone;
2190   for(unsigned int i=1; i < args.size(); ++i)
2191     {
2192     if(args[i] == "FILE")
2193       {
2194       doing = DoingFile;
2195       }
2196     else if(doing == DoingFile)
2197       {
2198       file = args[i].c_str();
2199       doing = DoingNone;
2200       }
2201     else
2202       {
2203       cmOStringStream e;
2204       e << "RPATH_REMOVE given unknown argument " << args[i];
2205       this->SetError(e.str().c_str());
2206       return false;
2207       }
2208     }
2209   if(!file)
2210     {
2211     this->SetError("RPATH_REMOVE not given FILE option.");
2212     return false;
2213     }
2214   if(!cmSystemTools::FileExists(file, true))
2215     {
2216     cmOStringStream e;
2217     e << "RPATH_REMOVE given FILE \"" << file << "\" that does not exist.";
2218     this->SetError(e.str().c_str());
2219     return false;
2220     }
2221   bool success = true;
2222   cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
2223   bool have_ft = cmSystemTools::FileTimeGet(file, ft);
2224   std::string emsg;
2225   bool removed;
2226   if(!cmSystemTools::RemoveRPath(file, &emsg, &removed))
2227     {
2228     cmOStringStream e;
2229     e << "RPATH_REMOVE could not remove RPATH from file:\n"
2230       << "  " << file << "\n"
2231       << emsg;
2232     this->SetError(e.str().c_str());
2233     success = false;
2234     }
2235   if(success)
2236     {
2237     if(removed)
2238       {
2239       std::string message = "Removed runtime path from \"";
2240       message += file;
2241       message += "\"";
2242       this->Makefile->DisplayStatus(message.c_str(), -1);
2243       }
2244     if(have_ft)
2245       {
2246       cmSystemTools::FileTimeSet(file, ft);
2247       }
2248     }
2249   cmSystemTools::FileTimeDelete(ft);
2250   return success;
2251 }
2252
2253 //----------------------------------------------------------------------------
2254 bool
2255 cmFileCommand::HandleRPathCheckCommand(std::vector<std::string> const& args)
2256 {
2257   // Evaluate arguments.
2258   const char* file = 0;
2259   const char* rpath = 0;
2260   enum Doing { DoingNone, DoingFile, DoingRPath };
2261   Doing doing = DoingNone;
2262   for(unsigned int i=1; i < args.size(); ++i)
2263     {
2264     if(args[i] == "RPATH")
2265       {
2266       doing = DoingRPath;
2267       }
2268     else if(args[i] == "FILE")
2269       {
2270       doing = DoingFile;
2271       }
2272     else if(doing == DoingFile)
2273       {
2274       file = args[i].c_str();
2275       doing = DoingNone;
2276       }
2277     else if(doing == DoingRPath)
2278       {
2279       rpath = args[i].c_str();
2280       doing = DoingNone;
2281       }
2282     else
2283       {
2284       cmOStringStream e;
2285       e << "RPATH_CHECK given unknown argument " << args[i];
2286       this->SetError(e.str().c_str());
2287       return false;
2288       }
2289     }
2290   if(!file)
2291     {
2292     this->SetError("RPATH_CHECK not given FILE option.");
2293     return false;
2294     }
2295   if(!rpath)
2296     {
2297     this->SetError("RPATH_CHECK not given RPATH option.");
2298     return false;
2299     }
2300
2301   // If the file exists but does not have the desired RPath then
2302   // delete it.  This is used during installation to re-install a file
2303   // if its RPath will change.
2304   if(cmSystemTools::FileExists(file, true) &&
2305      !cmSystemTools::CheckRPath(file, rpath))
2306     {
2307     cmSystemTools::RemoveFile(file);
2308     }
2309
2310   return true;
2311 }
2312
2313 //----------------------------------------------------------------------------
2314 bool cmFileCommand::HandleInstallCommand(std::vector<std::string> const& args)
2315 {
2316   cmFileInstaller installer(this);
2317   return installer.Run(args);
2318 }
2319
2320 //----------------------------------------------------------------------------
2321 bool cmFileCommand::HandleRelativePathCommand(
2322   std::vector<std::string> const& args)
2323 {
2324   if(args.size() != 4 )
2325     {
2326     this->SetError("RELATIVE_PATH called with incorrect number of arguments");
2327     return false;
2328     }
2329
2330   const std::string& outVar = args[1];
2331   const std::string& directoryName = args[2];
2332   const std::string& fileName = args[3];
2333
2334   if(!cmSystemTools::FileIsFullPath(directoryName.c_str()))
2335     {
2336     std::string errstring =
2337       "RELATIVE_PATH must be passed a full path to the directory: "
2338       + directoryName;
2339     this->SetError(errstring.c_str());
2340     return false;
2341     }
2342   if(!cmSystemTools::FileIsFullPath(fileName.c_str()))
2343     {
2344     std::string errstring =
2345       "RELATIVE_PATH must be passed a full path to the file: "
2346       + fileName;
2347     this->SetError(errstring.c_str());
2348     return false;
2349     }
2350
2351   std::string res = cmSystemTools::RelativePath(directoryName.c_str(),
2352                                                 fileName.c_str());
2353   this->Makefile->AddDefinition(outVar.c_str(),
2354     res.c_str());
2355   return true;
2356 }
2357
2358
2359 //----------------------------------------------------------------------------
2360 bool cmFileCommand::HandleRename(std::vector<std::string> const& args)
2361 {
2362   if(args.size() != 3)
2363     {
2364     this->SetError("RENAME given incorrect number of arguments.");
2365     return false;
2366     }
2367
2368   // Compute full path for old and new names.
2369   std::string oldname = args[1];
2370   if(!cmsys::SystemTools::FileIsFullPath(oldname.c_str()))
2371     {
2372     oldname = this->Makefile->GetCurrentDirectory();
2373     oldname += "/" + args[1];
2374     }
2375   std::string newname = args[2];
2376   if(!cmsys::SystemTools::FileIsFullPath(newname.c_str()))
2377     {
2378     newname = this->Makefile->GetCurrentDirectory();
2379     newname += "/" + args[2];
2380     }
2381
2382   if(!cmSystemTools::RenameFile(oldname.c_str(), newname.c_str()))
2383     {
2384     std::string err = cmSystemTools::GetLastSystemError();
2385     cmOStringStream e;
2386     e << "RENAME failed to rename\n"
2387       << "  " << oldname << "\n"
2388       << "to\n"
2389       << "  " << newname << "\n"
2390       << "because: " << err << "\n";
2391     this->SetError(e.str().c_str());
2392     return false;
2393     }
2394   return true;
2395 }
2396
2397
2398 //----------------------------------------------------------------------------
2399 bool cmFileCommand::HandleRemove(std::vector<std::string> const& args,
2400                                  bool recurse)
2401 {
2402
2403   std::string message;
2404   std::vector<std::string>::const_iterator i = args.begin();
2405
2406   i++; // Get rid of subcommand
2407   for(;i != args.end(); ++i)
2408     {
2409     std::string fileName = *i;
2410     if(!cmsys::SystemTools::FileIsFullPath(fileName.c_str()))
2411       {
2412       fileName = this->Makefile->GetCurrentDirectory();
2413       fileName += "/" + *i;
2414       }
2415
2416     if(cmSystemTools::FileIsDirectory(fileName.c_str()) &&
2417        !cmSystemTools::FileIsSymlink(fileName.c_str()) && recurse)
2418       {
2419       cmSystemTools::RemoveADirectory(fileName.c_str());
2420       }
2421     else
2422       {
2423       cmSystemTools::RemoveFile(fileName.c_str());
2424       }
2425     }
2426   return true;
2427 }
2428
2429 //----------------------------------------------------------------------------
2430 bool cmFileCommand::HandleCMakePathCommand(std::vector<std::string>
2431                                            const& args,
2432                                            bool nativePath)
2433 {
2434   std::vector<std::string>::const_iterator i = args.begin();
2435   if(args.size() != 3)
2436     {
2437     this->SetError("FILE([TO_CMAKE_PATH|TO_NATIVE_PATH] path result) must be "
2438       "called with exactly three arguments.");
2439     return false;
2440     }
2441   i++; // Get rid of subcommand
2442 #if defined(_WIN32) && !defined(__CYGWIN__)
2443   char pathSep = ';';
2444 #else
2445   char pathSep = ':';
2446 #endif
2447   std::vector<cmsys::String> path = cmSystemTools::SplitString(i->c_str(),
2448                                                              pathSep);
2449   i++;
2450   const char* var =  i->c_str();
2451   std::string value;
2452   for(std::vector<cmsys::String>::iterator j = path.begin();
2453       j != path.end(); ++j)
2454     {
2455     if(j != path.begin())
2456       {
2457       value += ";";
2458       }
2459     if(!nativePath)
2460       {
2461       cmSystemTools::ConvertToUnixSlashes(*j);
2462       }
2463     else
2464       {
2465       *j = cmSystemTools::ConvertToOutputPath(j->c_str());
2466       // remove double quotes in the path
2467       cmsys::String& s = *j;
2468
2469       if(s.size() > 1 && s[0] == '\"' && s[s.size()-1] == '\"')
2470         {
2471         s = s.substr(1,s.size()-2);
2472         }
2473       }
2474     value += *j;
2475     }
2476   this->Makefile->AddDefinition(var, value.c_str());
2477   return true;
2478 }
2479
2480
2481 #if defined(CMAKE_BUILD_WITH_CMAKE)
2482
2483 // Stuff for curl download/upload
2484 typedef std::vector<char> cmFileCommandVectorOfChar;
2485
2486 namespace {
2487
2488   size_t
2489   cmWriteToFileCallback(void *ptr, size_t size, size_t nmemb,
2490                         void *data)
2491     {
2492     int realsize = (int)(size * nmemb);
2493     std::ofstream* fout = static_cast<std::ofstream*>(data);
2494     const char* chPtr = static_cast<char*>(ptr);
2495     fout->write(chPtr, realsize);
2496     return realsize;
2497     }
2498
2499
2500   size_t
2501   cmWriteToMemoryCallback(void *ptr, size_t size, size_t nmemb,
2502                           void *data)
2503     {
2504     int realsize = (int)(size * nmemb);
2505     cmFileCommandVectorOfChar *vec
2506       = static_cast<cmFileCommandVectorOfChar*>(data);
2507     const char* chPtr = static_cast<char*>(ptr);
2508     vec->insert(vec->end(), chPtr, chPtr + realsize);
2509     return realsize;
2510     }
2511
2512
2513   static size_t
2514   cmFileCommandCurlDebugCallback(CURL *, curl_infotype, char *chPtr,
2515                                  size_t size, void *data)
2516     {
2517     cmFileCommandVectorOfChar *vec
2518       = static_cast<cmFileCommandVectorOfChar*>(data);
2519     vec->insert(vec->end(), chPtr, chPtr + size);
2520     return size;
2521     }
2522
2523
2524   class cURLProgressHelper
2525   {
2526   public:
2527     cURLProgressHelper(cmFileCommand *fc, const char *text)
2528       {
2529       this->CurrentPercentage = -1;
2530       this->FileCommand = fc;
2531       this->Text = text;
2532       }
2533
2534     bool UpdatePercentage(double value, double total, std::string &status)
2535       {
2536       int OldPercentage = this->CurrentPercentage;
2537
2538       if (total > 0.0)
2539         {
2540         this->CurrentPercentage = static_cast<int>(value/total*100.0 + 0.5);
2541         }
2542
2543       bool updated = (OldPercentage != this->CurrentPercentage);
2544
2545       if (updated)
2546         {
2547         cmOStringStream oss;
2548         oss << "[" << this->Text << " " << this->CurrentPercentage
2549             << "% complete]";
2550         status = oss.str();
2551         }
2552
2553       return updated;
2554       }
2555
2556     cmFileCommand *GetFileCommand()
2557       {
2558       return this->FileCommand;
2559       }
2560
2561   private:
2562     int CurrentPercentage;
2563     cmFileCommand *FileCommand;
2564     std::string Text;
2565   };
2566
2567
2568   static int
2569   cmFileDownloadProgressCallback(void *clientp,
2570                                  double dltotal, double dlnow,
2571                                  double ultotal, double ulnow)
2572     {
2573     cURLProgressHelper *helper =
2574       reinterpret_cast<cURLProgressHelper *>(clientp);
2575
2576     static_cast<void>(ultotal);
2577     static_cast<void>(ulnow);
2578
2579     std::string status;
2580     if (helper->UpdatePercentage(dlnow, dltotal, status))
2581       {
2582       cmFileCommand *fc = helper->GetFileCommand();
2583       cmMakefile *mf = fc->GetMakefile();
2584       mf->DisplayStatus(status.c_str(), -1);
2585       }
2586
2587     return 0;
2588     }
2589
2590
2591   static int
2592   cmFileUploadProgressCallback(void *clientp,
2593                                double dltotal, double dlnow,
2594                                double ultotal, double ulnow)
2595     {
2596     cURLProgressHelper *helper =
2597     reinterpret_cast<cURLProgressHelper *>(clientp);
2598
2599     static_cast<void>(dltotal);
2600     static_cast<void>(dlnow);
2601
2602     std::string status;
2603     if (helper->UpdatePercentage(ulnow, ultotal, status))
2604       {
2605       cmFileCommand *fc = helper->GetFileCommand();
2606       cmMakefile *mf = fc->GetMakefile();
2607       mf->DisplayStatus(status.c_str(), -1);
2608       }
2609
2610     return 0;
2611     }
2612 }
2613
2614
2615 namespace {
2616
2617   class cURLEasyGuard
2618   {
2619   public:
2620     cURLEasyGuard(CURL * easy)
2621       : Easy(easy)
2622       {}
2623
2624     ~cURLEasyGuard(void)
2625       {
2626         if (this->Easy)
2627           {
2628           ::curl_easy_cleanup(this->Easy);
2629           }
2630       }
2631
2632     inline void release(void)
2633       {
2634         this->Easy = 0;
2635         return;
2636       }
2637
2638   private:
2639     ::CURL * Easy;
2640   };
2641
2642 }
2643 #endif
2644
2645
2646 #define check_curl_result(result, errstr) \
2647   if (result != CURLE_OK)                 \
2648     {                                     \
2649     std::string e(errstr);                \
2650     e += ::curl_easy_strerror(result);    \
2651     this->SetError(e.c_str());            \
2652     return false;                         \
2653     }
2654
2655
2656 bool
2657 cmFileCommand::HandleDownloadCommand(std::vector<std::string> const& args)
2658 {
2659 #if defined(CMAKE_BUILD_WITH_CMAKE)
2660   std::vector<std::string>::const_iterator i = args.begin();
2661   if(args.size() < 3)
2662     {
2663     this->SetError("DOWNLOAD must be called with at least three arguments.");
2664     return false;
2665     }
2666   ++i; // Get rid of subcommand
2667   std::string url = *i;
2668   ++i;
2669   std::string file = *i;
2670   ++i;
2671
2672   long timeout = 0;
2673   long inactivity_timeout = 0;
2674   std::string verboseLog;
2675   std::string statusVar;
2676   bool tls_verify = this->Makefile->IsOn("CMAKE_TLS_VERIFY");
2677   const char* cainfo = this->Makefile->GetDefinition("CMAKE_TLS_CAINFO");
2678   std::string expectedHash;
2679   std::string hashMatchMSG;
2680   cmsys::auto_ptr<cmCryptoHash> hash;
2681   bool showProgress = false;
2682
2683   while(i != args.end())
2684     {
2685     if(*i == "TIMEOUT")
2686       {
2687       ++i;
2688       if(i != args.end())
2689         {
2690         timeout = atol(i->c_str());
2691         }
2692       else
2693         {
2694         this->SetError("DOWNLOAD missing time for TIMEOUT.");
2695         return false;
2696         }
2697       }
2698     else if(*i == "INACTIVITY_TIMEOUT")
2699       {
2700       ++i;
2701       if(i != args.end())
2702         {
2703         inactivity_timeout = atol(i->c_str());
2704         }
2705       else
2706         {
2707         this->SetError("DOWNLOAD missing time for INACTIVITY_TIMEOUT.");
2708         return false;
2709         }
2710       }
2711     else if(*i == "LOG")
2712       {
2713       ++i;
2714       if( i == args.end())
2715         {
2716         this->SetError("DOWNLOAD missing VAR for LOG.");
2717         return false;
2718         }
2719       verboseLog = *i;
2720       }
2721     else if(*i == "STATUS")
2722       {
2723       ++i;
2724       if( i == args.end())
2725         {
2726         this->SetError("DOWNLOAD missing VAR for STATUS.");
2727         return false;
2728         }
2729       statusVar = *i;
2730       }
2731     else if(*i == "TLS_VERIFY")
2732       {
2733       ++i;
2734       if(i != args.end())
2735         {
2736         tls_verify = cmSystemTools::IsOn(i->c_str());
2737         }
2738       else
2739         {
2740         this->SetError("TLS_VERIFY missing bool value.");
2741         return false;
2742         }
2743       }
2744     else if(*i == "TLS_CAINFO")
2745       {
2746       ++i;
2747       if(i != args.end())
2748         {
2749         cainfo = i->c_str();
2750         }
2751       else
2752         {
2753         this->SetError("TLS_CAFILE missing file value.");
2754         return false;
2755         }
2756       }
2757     else if(*i == "EXPECTED_MD5")
2758       {
2759       ++i;
2760       if( i == args.end())
2761         {
2762         this->SetError("DOWNLOAD missing sum value for EXPECTED_MD5.");
2763         return false;
2764         }
2765       hash = cmsys::auto_ptr<cmCryptoHash>(cmCryptoHash::New("MD5"));
2766       hashMatchMSG = "MD5 sum";
2767       expectedHash = cmSystemTools::LowerCase(*i);
2768       }
2769     else if(*i == "SHOW_PROGRESS")
2770       {
2771       showProgress = true;
2772       }
2773     else if(*i == "EXPECTED_HASH")
2774       {
2775       ++i;
2776       if(i == args.end())
2777         {
2778         this->SetError("DOWNLOAD missing ALGO=value for EXPECTED_HASH.");
2779         return false;
2780         }
2781       std::string::size_type pos = i->find("=");
2782       if(pos == std::string::npos)
2783         {
2784         std::string err =
2785           "DOWNLOAD EXPECTED_HASH expects ALGO=value but got: ";
2786         err += *i;
2787         this->SetError(err.c_str());
2788         return false;
2789         }
2790       std::string algo = i->substr(0, pos);
2791       expectedHash = cmSystemTools::LowerCase(i->substr(pos+1));
2792       hash = cmsys::auto_ptr<cmCryptoHash>(cmCryptoHash::New(algo.c_str()));
2793       if(!hash.get())
2794         {
2795         std::string err = "DOWNLOAD EXPECTED_HASH given unknown ALGO: ";
2796         err += algo;
2797         this->SetError(err.c_str());
2798         return false;
2799         }
2800       hashMatchMSG = algo + " hash";
2801       }
2802     ++i;
2803     }
2804   // If file exists already, and caller specified an expected md5 or sha,
2805   // and the existing file already has the expected hash, then simply
2806   // return.
2807   //
2808   if(cmSystemTools::FileExists(file.c_str()) && hash.get())
2809     {
2810     std::string msg;
2811     std::string actualHash = hash->HashFile(file.c_str());
2812     if(actualHash == expectedHash)
2813       {
2814       msg = "returning early; file already exists with expected ";
2815       msg += hashMatchMSG;
2816       msg += "\"";
2817       if(statusVar.size())
2818         {
2819         cmOStringStream result;
2820         result << (int)0 << ";\"" << msg;
2821         this->Makefile->AddDefinition(statusVar.c_str(),
2822                                       result.str().c_str());
2823         }
2824       return true;
2825       }
2826     }
2827   // Make sure parent directory exists so we can write to the file
2828   // as we receive downloaded bits from curl...
2829   //
2830   std::string dir = cmSystemTools::GetFilenamePath(file.c_str());
2831   if(!cmSystemTools::FileExists(dir.c_str()) &&
2832      !cmSystemTools::MakeDirectory(dir.c_str()))
2833     {
2834     std::string errstring = "DOWNLOAD error: cannot create directory '"
2835       + dir + "' - Specify file by full path name and verify that you "
2836       "have directory creation and file write privileges.";
2837     this->SetError(errstring.c_str());
2838     return false;
2839     }
2840
2841   std::ofstream fout(file.c_str(), std::ios::binary);
2842   if(!fout)
2843     {
2844     this->SetError("DOWNLOAD cannot open file for write.");
2845     return false;
2846     }
2847
2848   ::CURL *curl;
2849   ::curl_global_init(CURL_GLOBAL_DEFAULT);
2850   curl = ::curl_easy_init();
2851   if(!curl)
2852     {
2853     this->SetError("DOWNLOAD error initializing curl.");
2854     return false;
2855     }
2856
2857   cURLEasyGuard g_curl(curl);
2858   ::CURLcode res = ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
2859   check_curl_result(res, "DOWNLOAD cannot set url: ");
2860
2861   // enable HTTP ERROR parsing
2862   res = ::curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
2863   check_curl_result(res, "DOWNLOAD cannot set http failure option: ");
2864
2865   res = ::curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl/" LIBCURL_VERSION);
2866   check_curl_result(res, "DOWNLOAD cannot set user agent option: ");
2867
2868   res = ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
2869                            cmWriteToFileCallback);
2870   check_curl_result(res, "DOWNLOAD cannot set write function: ");
2871
2872   res = ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
2873                            cmFileCommandCurlDebugCallback);
2874   check_curl_result(res, "DOWNLOAD cannot set debug function: ");
2875
2876   // check to see if TLS verification is requested
2877   if(tls_verify)
2878     {
2879     res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
2880     check_curl_result(res, "Unable to set TLS/SSL Verify on: ");
2881     }
2882   else
2883     {
2884     res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
2885     check_curl_result(res, "Unable to set TLS/SSL Verify off: ");
2886     }
2887   // check to see if a CAINFO file has been specified
2888   // command arg comes first
2889   if(cainfo && *cainfo)
2890     {
2891     res = ::curl_easy_setopt(curl, CURLOPT_CAINFO, cainfo);
2892     check_curl_result(res, "Unable to set TLS/SSL Verify CAINFO: ");
2893     }
2894
2895   cmFileCommandVectorOfChar chunkDebug;
2896
2897   res = ::curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&fout);
2898   check_curl_result(res, "DOWNLOAD cannot set write data: ");
2899
2900   res = ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
2901   check_curl_result(res, "DOWNLOAD cannot set debug data: ");
2902
2903   res = ::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
2904   check_curl_result(res, "DOWNLOAD cannot set follow-redirect option: ");
2905
2906   if(verboseLog.size())
2907     {
2908     res = ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
2909     check_curl_result(res, "DOWNLOAD cannot set verbose: ");
2910     }
2911
2912   if(timeout > 0)
2913     {
2914     res = ::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout );
2915     check_curl_result(res, "DOWNLOAD cannot set timeout: ");
2916     }
2917
2918   if(inactivity_timeout > 0)
2919     {
2920     // Give up if there is no progress for a long time.
2921     ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
2922     ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, inactivity_timeout);
2923     }
2924
2925   // Need the progress helper's scope to last through the duration of
2926   // the curl_easy_perform call... so this object is declared at function
2927   // scope intentionally, rather than inside the "if(showProgress)"
2928   // block...
2929   //
2930   cURLProgressHelper helper(this, "download");
2931
2932   if(showProgress)
2933     {
2934     res = ::curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
2935     check_curl_result(res, "DOWNLOAD cannot set noprogress value: ");
2936
2937     res = ::curl_easy_setopt(curl,
2938       CURLOPT_PROGRESSFUNCTION, cmFileDownloadProgressCallback);
2939     check_curl_result(res, "DOWNLOAD cannot set progress function: ");
2940
2941     res = ::curl_easy_setopt(curl,
2942       CURLOPT_PROGRESSDATA, reinterpret_cast<void*>(&helper));
2943     check_curl_result(res, "DOWNLOAD cannot set progress data: ");
2944     }
2945
2946   res = ::curl_easy_perform(curl);
2947
2948   /* always cleanup */
2949   g_curl.release();
2950   ::curl_easy_cleanup(curl);
2951
2952   if(statusVar.size())
2953     {
2954     cmOStringStream result;
2955     result << (int)res << ";\"" << ::curl_easy_strerror(res) << "\"";
2956     this->Makefile->AddDefinition(statusVar.c_str(),
2957                                   result.str().c_str());
2958     }
2959
2960   ::curl_global_cleanup();
2961
2962   // Explicitly flush/close so we can measure the md5 accurately.
2963   //
2964   fout.flush();
2965   fout.close();
2966
2967   // Verify MD5 sum if requested:
2968   //
2969   if (hash.get())
2970     {
2971     std::string actualHash = hash->HashFile(file.c_str());
2972     if (actualHash.size() == 0)
2973       {
2974       this->SetError("DOWNLOAD cannot compute hash on downloaded file");
2975       return false;
2976       }
2977
2978     if (expectedHash != actualHash)
2979       {
2980       cmOStringStream oss;
2981       oss << "DOWNLOAD HASH mismatch" << std::endl
2982         << "  for file: [" << file << "]" << std::endl
2983         << "    expected hash: [" << expectedHash << "]" << std::endl
2984         << "      actual hash: [" << actualHash << "]" << std::endl
2985         ;
2986       this->SetError(oss.str().c_str());
2987       return false;
2988       }
2989     }
2990
2991   if(chunkDebug.size())
2992     {
2993     chunkDebug.push_back(0);
2994     if(CURLE_OPERATION_TIMEOUTED == res)
2995       {
2996       std::string output = &*chunkDebug.begin();
2997
2998       if(verboseLog.size())
2999         {
3000         this->Makefile->AddDefinition(verboseLog.c_str(),
3001                                       &*chunkDebug.begin());
3002         }
3003       }
3004
3005     this->Makefile->AddDefinition(verboseLog.c_str(),
3006                                   &*chunkDebug.begin());
3007     }
3008
3009   return true;
3010 #else
3011   this->SetError("DOWNLOAD not supported by bootstrap cmake.");
3012   return false;
3013 #endif
3014 }
3015
3016
3017 bool
3018 cmFileCommand::HandleUploadCommand(std::vector<std::string> const& args)
3019 {
3020 #if defined(CMAKE_BUILD_WITH_CMAKE)
3021   if(args.size() < 3)
3022     {
3023     this->SetError("UPLOAD must be called with at least three arguments.");
3024     return false;
3025     }
3026   std::vector<std::string>::const_iterator i = args.begin();
3027   ++i;
3028   std::string filename = *i;
3029   ++i;
3030   std::string url = *i;
3031   ++i;
3032
3033   long timeout = 0;
3034   long inactivity_timeout = 0;
3035   std::string logVar;
3036   std::string statusVar;
3037   bool showProgress = false;
3038
3039   while(i != args.end())
3040     {
3041     if(*i == "TIMEOUT")
3042       {
3043       ++i;
3044       if(i != args.end())
3045         {
3046         timeout = atol(i->c_str());
3047         }
3048       else
3049         {
3050         this->SetError("UPLOAD missing time for TIMEOUT.");
3051         return false;
3052         }
3053       }
3054     else if(*i == "INACTIVITY_TIMEOUT")
3055       {
3056       ++i;
3057       if(i != args.end())
3058         {
3059         inactivity_timeout = atol(i->c_str());
3060         }
3061       else
3062         {
3063         this->SetError("UPLOAD missing time for INACTIVITY_TIMEOUT.");
3064         return false;
3065         }
3066       }
3067     else if(*i == "LOG")
3068       {
3069       ++i;
3070       if( i == args.end())
3071         {
3072         this->SetError("UPLOAD missing VAR for LOG.");
3073         return false;
3074         }
3075       logVar = *i;
3076       }
3077     else if(*i == "STATUS")
3078       {
3079       ++i;
3080       if( i == args.end())
3081         {
3082         this->SetError("UPLOAD missing VAR for STATUS.");
3083         return false;
3084         }
3085       statusVar = *i;
3086       }
3087     else if(*i == "SHOW_PROGRESS")
3088       {
3089       showProgress = true;
3090       }
3091
3092     ++i;
3093     }
3094
3095   // Open file for reading:
3096   //
3097   FILE *fin = fopen(filename.c_str(), "rb");
3098   if(!fin)
3099     {
3100     std::string errStr = "UPLOAD cannot open file '";
3101     errStr += filename + "' for reading.";
3102     this->SetError(errStr.c_str());
3103     return false;
3104     }
3105
3106   struct stat st;
3107   if(::stat(filename.c_str(), &st))
3108     {
3109     std::string errStr = "UPLOAD cannot stat file '";
3110     errStr += filename + "'.";
3111     this->SetError(errStr.c_str());
3112     fclose(fin);
3113     return false;
3114     }
3115
3116   ::CURL *curl;
3117   ::curl_global_init(CURL_GLOBAL_DEFAULT);
3118   curl = ::curl_easy_init();
3119   if(!curl)
3120     {
3121     this->SetError("UPLOAD error initializing curl.");
3122     fclose(fin);
3123     return false;
3124     }
3125
3126   cURLEasyGuard g_curl(curl);
3127
3128   // enable HTTP ERROR parsing
3129   ::CURLcode res = ::curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
3130
3131   // enable uploading
3132   res = ::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
3133   check_curl_result(res, "UPLOAD cannot set upload flag: ");
3134
3135   res = ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
3136   check_curl_result(res, "UPLOAD cannot set url: ");
3137
3138   res = ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
3139                            cmWriteToMemoryCallback);
3140   check_curl_result(res, "UPLOAD cannot set write function: ");
3141
3142   res = ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
3143                            cmFileCommandCurlDebugCallback);
3144   check_curl_result(res, "UPLOAD cannot set debug function: ");
3145
3146   cmFileCommandVectorOfChar chunkResponse;
3147   cmFileCommandVectorOfChar chunkDebug;
3148
3149   res = ::curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunkResponse);
3150   check_curl_result(res, "UPLOAD cannot set write data: ");
3151
3152   res = ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
3153   check_curl_result(res, "UPLOAD cannot set debug data: ");
3154
3155   res = ::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
3156   check_curl_result(res, "UPLOAD cannot set follow-redirect option: ");
3157
3158   if(logVar.size())
3159     {
3160     res = ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
3161     check_curl_result(res, "UPLOAD cannot set verbose: ");
3162     }
3163
3164   if(timeout > 0)
3165     {
3166     res = ::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout );
3167     check_curl_result(res, "UPLOAD cannot set timeout: ");
3168     }
3169
3170   if(inactivity_timeout > 0)
3171     {
3172     // Give up if there is no progress for a long time.
3173     ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
3174     ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, inactivity_timeout);
3175     }
3176
3177   // Need the progress helper's scope to last through the duration of
3178   // the curl_easy_perform call... so this object is declared at function
3179   // scope intentionally, rather than inside the "if(showProgress)"
3180   // block...
3181   //
3182   cURLProgressHelper helper(this, "upload");
3183
3184   if(showProgress)
3185     {
3186     res = ::curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
3187     check_curl_result(res, "UPLOAD cannot set noprogress value: ");
3188
3189     res = ::curl_easy_setopt(curl,
3190       CURLOPT_PROGRESSFUNCTION, cmFileUploadProgressCallback);
3191     check_curl_result(res, "UPLOAD cannot set progress function: ");
3192
3193     res = ::curl_easy_setopt(curl,
3194       CURLOPT_PROGRESSDATA, reinterpret_cast<void*>(&helper));
3195     check_curl_result(res, "UPLOAD cannot set progress data: ");
3196     }
3197
3198   // now specify which file to upload
3199   res = ::curl_easy_setopt(curl, CURLOPT_INFILE, fin);
3200   check_curl_result(res, "UPLOAD cannot set input file: ");
3201
3202   // and give the size of the upload (optional)
3203   res = ::curl_easy_setopt(curl,
3204     CURLOPT_INFILESIZE, static_cast<long>(st.st_size));
3205   check_curl_result(res, "UPLOAD cannot set input file size: ");
3206
3207   res = ::curl_easy_perform(curl);
3208
3209   /* always cleanup */
3210   g_curl.release();
3211   ::curl_easy_cleanup(curl);
3212
3213   if(statusVar.size())
3214     {
3215     cmOStringStream result;
3216     result << (int)res << ";\"" << ::curl_easy_strerror(res) << "\"";
3217     this->Makefile->AddDefinition(statusVar.c_str(),
3218                                   result.str().c_str());
3219     }
3220
3221   ::curl_global_cleanup();
3222
3223   fclose(fin);
3224   fin = NULL;
3225
3226   if(logVar.size())
3227     {
3228     std::string log;
3229
3230     if(chunkResponse.size())
3231       {
3232       chunkResponse.push_back(0);
3233       log += "Response:\n";
3234       log += &*chunkResponse.begin();
3235       log += "\n";
3236       }
3237
3238     if(chunkDebug.size())
3239       {
3240       chunkDebug.push_back(0);
3241       log += "Debug:\n";
3242       log += &*chunkDebug.begin();
3243       log += "\n";
3244       }
3245
3246     this->Makefile->AddDefinition(logVar.c_str(), log.c_str());
3247     }
3248
3249   return true;
3250 #else
3251   this->SetError("UPLOAD not supported by bootstrap cmake.");
3252   return false;
3253 #endif
3254 }
3255
3256 //----------------------------------------------------------------------------
3257 void cmFileCommand::AddEvaluationFile(const std::string &inputName,
3258                                       const std::string &outputExpr,
3259                                       const std::string &condition,
3260                                       bool inputIsContent
3261                                      )
3262 {
3263   cmListFileBacktrace lfbt;
3264   this->Makefile->GetBacktrace(lfbt);
3265
3266   cmGeneratorExpression outputGe(lfbt);
3267   cmsys::auto_ptr<cmCompiledGeneratorExpression> outputCge
3268                                                 = outputGe.Parse(outputExpr);
3269
3270   cmGeneratorExpression conditionGe(lfbt);
3271   cmsys::auto_ptr<cmCompiledGeneratorExpression> conditionCge
3272                                               = conditionGe.Parse(condition);
3273
3274   this->Makefile->GetLocalGenerator()
3275                 ->GetGlobalGenerator()->AddEvaluationFile(inputName,
3276                                                           outputCge,
3277                                                           this->Makefile,
3278                                                           conditionCge,
3279                                                           inputIsContent);
3280 }
3281
3282 //----------------------------------------------------------------------------
3283 bool cmFileCommand::HandleGenerateCommand(
3284   std::vector<std::string> const& args)
3285 {
3286   if (args.size() < 5)
3287     {
3288     this->SetError("Incorrect arguments to GENERATE subcommand.");
3289     return false;
3290     }
3291   if (args[1] != "OUTPUT")
3292     {
3293     this->SetError("Incorrect arguments to GENERATE subcommand.");
3294     return false;
3295     }
3296   std::string condition;
3297   if (args.size() > 5)
3298     {
3299     if (args[5] != "CONDITION")
3300       {
3301       this->SetError("Incorrect arguments to GENERATE subcommand.");
3302       return false;
3303       }
3304     if (args.size() != 7)
3305       {
3306       this->SetError("Incorrect arguments to GENERATE subcommand.");
3307       return false;
3308       }
3309     condition = args[6];
3310     if (condition.empty())
3311       {
3312       this->SetError("CONDITION of sub-command GENERATE must not be empty if "
3313         "specified.");
3314       return false;
3315       }
3316     }
3317   std::string output = args[2];
3318   const bool inputIsContent = args[3] != "INPUT";
3319   if (inputIsContent && args[3] != "CONTENT")
3320     {
3321     this->SetError("Incorrect arguments to GENERATE subcommand.");
3322     return false;
3323     }
3324   std::string input = args[4];
3325
3326   this->AddEvaluationFile(input, output, condition, inputIsContent);
3327   return true;
3328 }
3329
3330 //----------------------------------------------------------------------------
3331 bool cmFileCommand::HandleTimestampCommand(
3332   std::vector<std::string> const& args)
3333 {
3334   if(args.size() < 3)
3335     {
3336     this->SetError("sub-command TIMESTAMP requires at least two arguments.");
3337     return false;
3338     }
3339   else if(args.size() > 5)
3340     {
3341     this->SetError("sub-command TIMESTAMP takes at most four arguments.");
3342     return false;
3343     }
3344
3345   unsigned int argsIndex = 1;
3346
3347   const std::string& filename = args[argsIndex++];
3348
3349   const std::string& outputVariable = args[argsIndex++];
3350
3351   std::string formatString;
3352   if(args.size() > argsIndex && args[argsIndex] != "UTC")
3353     {
3354     formatString = args[argsIndex++];
3355     }
3356
3357   bool utcFlag = false;
3358   if(args.size() > argsIndex)
3359     {
3360     if(args[argsIndex] == "UTC")
3361       {
3362       utcFlag = true;
3363       }
3364     else
3365       {
3366       std::string e = " TIMESTAMP sub-command does not recognize option " +
3367           args[argsIndex] + ".";
3368       this->SetError(e.c_str());
3369       return false;
3370       }
3371     }
3372
3373   cmTimestamp timestamp;
3374   std::string result = timestamp.FileModificationTime(
3375     filename.c_str(), formatString, utcFlag);
3376   this->Makefile->AddDefinition(outputVariable.c_str(), result.c_str());
3377
3378   return true;
3379 }