cmListFileCache.cxx 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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 "cmListFileCache.h"
  14. #include "cmListFileLexer.h"
  15. #include "cmSystemTools.h"
  16. #include <cmsys/RegularExpression.hxx>
  17. bool cmListFileCacheParseFunction(cmListFileLexer* lexer,
  18. cmListFileFunction& function,
  19. const char* filename);
  20. cmListFileCache* cmListFileCache::Instance = 0;
  21. cmListFileCache* cmListFileCache::GetInstance()
  22. {
  23. if(!cmListFileCache::Instance)
  24. {
  25. cmListFileCache::Instance = new cmListFileCache;
  26. }
  27. return cmListFileCache::Instance;
  28. }
  29. void cmListFileCache::ClearCache()
  30. {
  31. delete cmListFileCache::Instance;
  32. cmListFileCache::Instance = 0;
  33. }
  34. cmListFile* cmListFileCache::GetFileCache(const char* path,
  35. bool requireProjectCommand)
  36. {
  37. ListFileMap::iterator sl = m_ListFileCache.find(path);
  38. if (sl == m_ListFileCache.end())
  39. {
  40. // if not already in the map, then parse and store the
  41. // file
  42. if(!this->CacheFile(path, requireProjectCommand))
  43. {
  44. return 0;
  45. }
  46. sl = m_ListFileCache.find(path);
  47. if (sl == m_ListFileCache.end())
  48. {
  49. cmSystemTools::Error("Fatal error, in cmListFileCache CacheFile failed",
  50. path);
  51. return 0;
  52. }
  53. }
  54. cmListFile& ret = sl->second;
  55. if(cmSystemTools::ModifiedTime(path) > ret.m_ModifiedTime )
  56. {
  57. if(!this->CacheFile(path, requireProjectCommand))
  58. {
  59. return 0;
  60. }
  61. else
  62. {
  63. sl = m_ListFileCache.find(path);
  64. return &sl->second;
  65. }
  66. }
  67. return &ret;
  68. }
  69. bool cmListFileCache::CacheFile(const char* path, bool requireProjectCommand)
  70. {
  71. if(!cmSystemTools::FileExists(path))
  72. {
  73. return false;
  74. }
  75. // Create the scanner.
  76. cmListFileLexer* lexer = cmListFileLexer_New();
  77. if(!lexer)
  78. {
  79. cmSystemTools::Error("cmListFileCache: error allocating lexer ");
  80. return false;
  81. }
  82. // Open the file.
  83. if(!cmListFileLexer_SetFileName(lexer, path))
  84. {
  85. cmListFileLexer_Delete(lexer);
  86. cmSystemTools::Error("cmListFileCache: error can not open file ", path);
  87. return false;
  88. }
  89. // Use a simple recursive-descent parser to process the token
  90. // stream.
  91. cmListFile inFile;
  92. inFile.m_ModifiedTime = cmSystemTools::ModifiedTime(path);
  93. bool parseError = false;
  94. bool haveNewline = true;
  95. cmListFileLexer_Token* token;
  96. while(!parseError && (token = cmListFileLexer_Scan(lexer)))
  97. {
  98. if(token->type == cmListFileLexer_Token_Newline)
  99. {
  100. haveNewline = true;
  101. }
  102. else if(token->type == cmListFileLexer_Token_Identifier)
  103. {
  104. if(haveNewline)
  105. {
  106. haveNewline = false;
  107. cmListFileFunction inFunction;
  108. inFunction.m_Name = token->text;
  109. inFunction.m_FilePath = path;
  110. inFunction.m_Line = token->line;
  111. if(cmListFileCacheParseFunction(lexer, inFunction, path))
  112. {
  113. inFile.m_Functions.push_back(inFunction);
  114. }
  115. else
  116. {
  117. parseError = true;
  118. }
  119. }
  120. else
  121. {
  122. cmOStringStream error;
  123. error << "Error in cmake code at\n"
  124. << path << ":" << token->line << ":\n"
  125. << "Parse error. Expected a newline, got \""
  126. << token->text << "\".";
  127. cmSystemTools::Error(error.str().c_str());
  128. parseError = true;
  129. }
  130. }
  131. else
  132. {
  133. cmOStringStream error;
  134. error << "Error in cmake code at\n"
  135. << path << ":" << token->line << ":\n"
  136. << "Parse error. Expected a command name, got \""
  137. << token->text << "\".";
  138. cmSystemTools::Error(error.str().c_str());
  139. parseError = true;
  140. }
  141. }
  142. if (parseError)
  143. {
  144. inFile.m_ModifiedTime = 0;
  145. }
  146. cmListFileLexer_Delete(lexer);
  147. if(requireProjectCommand)
  148. {
  149. bool hasProject = false;
  150. // search for a project command
  151. for(std::vector<cmListFileFunction>::iterator i
  152. = inFile.m_Functions.begin();
  153. i != inFile.m_Functions.end(); ++i)
  154. {
  155. if(i->m_Name == "PROJECT")
  156. {
  157. hasProject = true;
  158. break;
  159. }
  160. }
  161. // if no project command is found, add one
  162. if(!hasProject)
  163. {
  164. cmListFileFunction project;
  165. project.m_Name = "PROJECT";
  166. cmListFileArgument prj("Project", false);
  167. project.m_Arguments.push_back(prj);
  168. inFile.m_Functions.insert(inFile.m_Functions.begin(),project);
  169. }
  170. }
  171. m_ListFileCache[path] = inFile;
  172. return true;
  173. }
  174. void cmListFileCache::FlushCache(const char* path)
  175. {
  176. ListFileMap::iterator it = m_ListFileCache.find(path);
  177. if ( it != m_ListFileCache.end() )
  178. {
  179. m_ListFileCache.erase(it);
  180. return;
  181. }
  182. }
  183. bool cmListFileCacheParseFunction(cmListFileLexer* lexer,
  184. cmListFileFunction& function,
  185. const char* filename)
  186. {
  187. // Command name has already been parsed. Read the left paren.
  188. cmListFileLexer_Token* token;
  189. if(!(token = cmListFileLexer_Scan(lexer)))
  190. {
  191. cmOStringStream error;
  192. error << "Error in cmake code at\n"
  193. << filename << ":" << cmListFileLexer_GetCurrentLine(lexer) << ":\n"
  194. << "Parse error. Function missing opening \"(\".";
  195. cmSystemTools::Error(error.str().c_str());
  196. return false;
  197. }
  198. if(token->type != cmListFileLexer_Token_ParenLeft)
  199. {
  200. cmOStringStream error;
  201. error << "Error in cmake code at\n"
  202. << filename << ":" << cmListFileLexer_GetCurrentLine(lexer) << ":\n"
  203. << "Parse error. Expected \"(\", got \""
  204. << token->text << "\".";
  205. cmSystemTools::Error(error.str().c_str());
  206. return false;
  207. }
  208. // Arguments.
  209. while((token = cmListFileLexer_Scan(lexer)))
  210. {
  211. if(token->type == cmListFileLexer_Token_ParenRight)
  212. {
  213. return true;
  214. }
  215. else if(token->type == cmListFileLexer_Token_Identifier ||
  216. token->type == cmListFileLexer_Token_ArgumentUnquoted)
  217. {
  218. cmListFileArgument a(cmSystemTools::RemoveEscapes(token->text),
  219. false);
  220. function.m_Arguments.push_back(a);
  221. }
  222. else if(token->type == cmListFileLexer_Token_ArgumentQuoted)
  223. {
  224. cmListFileArgument a(cmSystemTools::RemoveEscapes(token->text),
  225. true);
  226. function.m_Arguments.push_back(a);
  227. }
  228. else if(token->type != cmListFileLexer_Token_Newline)
  229. {
  230. // Error.
  231. cmOStringStream error;
  232. error << "Error in cmake code at\n"
  233. << filename << ":" << cmListFileLexer_GetCurrentLine(lexer) << ":\n"
  234. << "Parse error. Function missing ending \")\". "
  235. << "Instead found \"" << token->text << "\".";
  236. cmSystemTools::Error(error.str().c_str());
  237. return false;
  238. }
  239. }
  240. cmOStringStream error;
  241. error << "Error in cmake code at\n"
  242. << filename << ":" << cmListFileLexer_GetCurrentLine(lexer) << ":\n"
  243. << "Parse error. Function missing ending \")\". "
  244. << "End of file reached.";
  245. cmSystemTools::Error(error.str().c_str());
  246. return false;
  247. }