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