You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

189 lines
5.2 KiB

  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmFileTimeComparison.h"
  14. // Use a hash table to avoid duplicate file time checks from disk.
  15. #if defined(CMAKE_BUILD_WITH_CMAKE)
  16. # include <cmsys/hash_map.hxx>
  17. #endif
  18. // Use a platform-specific API to get file times efficiently.
  19. #if !defined(_WIN32) || defined(__CYGWIN__)
  20. # define cmFileTimeComparison_Type struct stat
  21. # include <ctype.h>
  22. # include <sys/stat.h>
  23. #else
  24. # define cmFileTimeComparison_Type FILETIME
  25. # include <windows.h>
  26. #endif
  27. //----------------------------------------------------------------------------
  28. class cmFileTimeComparisonInternal
  29. {
  30. public:
  31. // Internal comparison method.
  32. inline bool FileTimeCompare(const char* f1, const char* f2, int* result);
  33. private:
  34. #if defined(CMAKE_BUILD_WITH_CMAKE)
  35. // Use a hash table to efficiently map from file name to modification time.
  36. class HashString
  37. {
  38. public:
  39. size_t operator()(const cmStdString& s) const
  40. {
  41. return h(s.c_str());
  42. }
  43. cmsys::hash<const char*> h;
  44. };
  45. typedef cmsys::hash_map<cmStdString,
  46. cmFileTimeComparison_Type, HashString> FileStatsMap;
  47. FileStatsMap Files;
  48. #endif
  49. // Internal methods to lookup and compare modification times.
  50. inline bool Stat(const char* fname, cmFileTimeComparison_Type* st);
  51. inline int Compare(cmFileTimeComparison_Type* st1,
  52. cmFileTimeComparison_Type* st2);
  53. };
  54. //----------------------------------------------------------------------------
  55. bool cmFileTimeComparisonInternal::Stat(const char* fname,
  56. cmFileTimeComparison_Type* st)
  57. {
  58. #if defined(CMAKE_BUILD_WITH_CMAKE)
  59. // Use the stored time if available.
  60. cmFileTimeComparisonInternal::FileStatsMap::iterator fit =
  61. this->Files.find(fname);
  62. if ( fit != this->Files.end() )
  63. {
  64. *st = fit->second;
  65. return true;
  66. }
  67. #endif
  68. #if !defined(_WIN32) || defined(__CYGWIN__)
  69. // POSIX version. Use the stat function.
  70. int res = ::stat(fname, st);
  71. if ( res != 0 )
  72. {
  73. return false;
  74. }
  75. #else
  76. // Windows version. Get the modification time from extended file
  77. // attributes.
  78. WIN32_FILE_ATTRIBUTE_DATA fdata;
  79. if(!GetFileAttributesEx(fname, GetFileExInfoStandard, &fdata))
  80. {
  81. return false;
  82. }
  83. // Copy the file time to the output location.
  84. *st = fdata.ftLastWriteTime;
  85. #endif
  86. #if defined(CMAKE_BUILD_WITH_CMAKE)
  87. // Store the time for future use.
  88. this->Files[fname] = *st;
  89. #endif
  90. return true;
  91. }
  92. //----------------------------------------------------------------------------
  93. cmFileTimeComparison::cmFileTimeComparison()
  94. {
  95. this->Internals = new cmFileTimeComparisonInternal;
  96. }
  97. //----------------------------------------------------------------------------
  98. cmFileTimeComparison::~cmFileTimeComparison()
  99. {
  100. delete this->Internals;
  101. }
  102. //----------------------------------------------------------------------------
  103. bool cmFileTimeComparison::FileTimeCompare(const char* f1,
  104. const char* f2, int* result)
  105. {
  106. return this->Internals->FileTimeCompare(f1, f2, result);
  107. }
  108. //----------------------------------------------------------------------------
  109. int cmFileTimeComparisonInternal::Compare(cmFileTimeComparison_Type* s1,
  110. cmFileTimeComparison_Type* s2)
  111. {
  112. #if !defined(_WIN32) || defined(__CYGWIN__)
  113. # if cmsys_STAT_HAS_ST_MTIM
  114. // Compare using nanosecond resolution.
  115. if(s1->st_mtim.tv_sec < s2->st_mtim.tv_sec)
  116. {
  117. return -1;
  118. }
  119. else if(s1->st_mtim.tv_sec > s2->st_mtim.tv_sec)
  120. {
  121. return 1;
  122. }
  123. else if(s1->st_mtim.tv_nsec < s2->st_mtim.tv_nsec)
  124. {
  125. return -1;
  126. }
  127. else if(s1->st_mtim.tv_nsec > s2->st_mtim.tv_nsec)
  128. {
  129. return 1;
  130. }
  131. # else
  132. // Compare using 1 second resolution.
  133. if(s1->st_mtime < s2->st_mtime)
  134. {
  135. return -1;
  136. }
  137. else if(s1->st_mtime > s2->st_mtime)
  138. {
  139. return 1;
  140. }
  141. # endif
  142. // Files have the same time.
  143. return 0;
  144. #else
  145. // Compare using system-provided function.
  146. return (int)CompareFileTime(s1, s2);
  147. #endif
  148. }
  149. //----------------------------------------------------------------------------
  150. bool cmFileTimeComparisonInternal::FileTimeCompare(const char* f1,
  151. const char* f2,
  152. int* result)
  153. {
  154. // Get the modification time for each file.
  155. cmFileTimeComparison_Type s1;
  156. cmFileTimeComparison_Type s2;
  157. if(this->Stat(f1, &s1) &&
  158. this->Stat(f2, &s2))
  159. {
  160. // Compare the two modification times.
  161. *result = this->Compare(&s1, &s2);
  162. return true;
  163. }
  164. else
  165. {
  166. // No comparison available. Default to the same time.
  167. *result = 0;
  168. return false;
  169. }
  170. }