cmListFileCache.cxx 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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. // Get a pointer to a persistent copy of the name.
  76. const char* filename = this->GetUniqueStringPointer(path);
  77. // Create the scanner.
  78. cmListFileLexer* lexer = cmListFileLexer_New();
  79. if(!lexer)
  80. {
  81. cmSystemTools::Error("cmListFileCache: error allocating lexer ");
  82. return false;
  83. }
  84. // Open the file.
  85. if(!cmListFileLexer_SetFileName(lexer, filename))
  86. {
  87. cmListFileLexer_Delete(lexer);
  88. cmSystemTools::Error("cmListFileCache: error can not open file ", filename);
  89. return false;
  90. }
  91. // Use a simple recursive-descent parser to process the token
  92. // stream.
  93. cmListFile inFile;
  94. inFile.m_ModifiedTime = cmSystemTools::ModifiedTime(filename);
  95. bool parseError = false;
  96. bool haveNewline = true;
  97. cmListFileLexer_Token* token;
  98. while(!parseError && (token = cmListFileLexer_Scan(lexer)))
  99. {
  100. if(token->type == cmListFileLexer_Token_Newline)
  101. {
  102. haveNewline = true;
  103. }
  104. else if(token->type == cmListFileLexer_Token_Identifier)
  105. {
  106. if(haveNewline)
  107. {
  108. haveNewline = false;
  109. cmListFileFunction inFunction;
  110. inFunction.m_Name = token->text;
  111. inFunction.m_FilePath = filename;
  112. inFunction.m_Line = token->line;
  113. if(cmListFileCacheParseFunction(lexer, inFunction, filename))
  114. {
  115. inFile.m_Functions.push_back(inFunction);
  116. }
  117. else
  118. {
  119. parseError = true;
  120. }
  121. }
  122. else
  123. {
  124. cmOStringStream error;
  125. error << "Error in cmake code at\n"
  126. << filename << ":" << token->line << ":\n"
  127. << "Parse error. Expected a newline, got "
  128. << cmListFileLexer_GetTypeAsString(lexer, token->type)
  129. << " with text \"" << token->text << "\".";
  130. cmSystemTools::Error(error.str().c_str());
  131. parseError = true;
  132. }
  133. }
  134. else
  135. {
  136. cmOStringStream error;
  137. error << "Error in cmake code at\n"
  138. << filename << ":" << token->line << ":\n"
  139. << "Parse error. Expected a command name, got "
  140. << cmListFileLexer_GetTypeAsString(lexer, token->type)
  141. << " with text \""
  142. << token->text << "\".";
  143. cmSystemTools::Error(error.str().c_str());
  144. parseError = true;
  145. }
  146. }
  147. if (parseError)
  148. {
  149. inFile.m_ModifiedTime = 0;
  150. }
  151. cmListFileLexer_Delete(lexer);
  152. if(requireProjectCommand)
  153. {
  154. bool hasProject = false;
  155. // search for a project command
  156. for(std::vector<cmListFileFunction>::iterator i
  157. = inFile.m_Functions.begin();
  158. i != inFile.m_Functions.end(); ++i)
  159. {
  160. if(i->m_Name == "PROJECT")
  161. {
  162. hasProject = true;
  163. break;
  164. }
  165. }
  166. // if no project command is found, add one
  167. if(!hasProject)
  168. {
  169. cmListFileFunction project;
  170. project.m_Name = "PROJECT";
  171. cmListFileArgument prj("Project", false, filename, 0);
  172. project.m_Arguments.push_back(prj);
  173. inFile.m_Functions.insert(inFile.m_Functions.begin(),project);
  174. }
  175. }
  176. m_ListFileCache[filename] = inFile;
  177. return true;
  178. }
  179. void cmListFileCache::FlushCache(const char* path)
  180. {
  181. ListFileMap::iterator it = m_ListFileCache.find(path);
  182. if ( it != m_ListFileCache.end() )
  183. {
  184. m_ListFileCache.erase(it);
  185. return;
  186. }
  187. }
  188. bool cmListFileCacheParseFunction(cmListFileLexer* lexer,
  189. cmListFileFunction& function,
  190. const char* filename)
  191. {
  192. // Command name has already been parsed. Read the left paren.
  193. cmListFileLexer_Token* token;
  194. if(!(token = cmListFileLexer_Scan(lexer)))
  195. {
  196. cmOStringStream error;
  197. error << "Error in cmake code at\n"
  198. << filename << ":" << cmListFileLexer_GetCurrentLine(lexer) << ":\n"
  199. << "Parse error. Function missing opening \"(\".";
  200. cmSystemTools::Error(error.str().c_str());
  201. return false;
  202. }
  203. if(token->type != cmListFileLexer_Token_ParenLeft)
  204. {
  205. cmOStringStream error;
  206. error << "Error in cmake code at\n"
  207. << filename << ":" << cmListFileLexer_GetCurrentLine(lexer) << ":\n"
  208. << "Parse error. Expected \"(\", got "
  209. << cmListFileLexer_GetTypeAsString(lexer, token->type)
  210. << " with text \"" << token->text << "\".";
  211. cmSystemTools::Error(error.str().c_str());
  212. return false;
  213. }
  214. // Arguments.
  215. unsigned long lastLine = cmListFileLexer_GetCurrentLine(lexer);
  216. while((token = cmListFileLexer_Scan(lexer)))
  217. {
  218. if(token->type == cmListFileLexer_Token_ParenRight)
  219. {
  220. return true;
  221. }
  222. else if(token->type == cmListFileLexer_Token_Identifier ||
  223. token->type == cmListFileLexer_Token_ArgumentUnquoted)
  224. {
  225. cmListFileArgument a(cmSystemTools::RemoveEscapes(token->text),
  226. false, filename, token->line);
  227. function.m_Arguments.push_back(a);
  228. }
  229. else if(token->type == cmListFileLexer_Token_ArgumentQuoted)
  230. {
  231. cmListFileArgument a(cmSystemTools::RemoveEscapes(token->text),
  232. true, filename, token->line);
  233. function.m_Arguments.push_back(a);
  234. }
  235. else if(token->type != cmListFileLexer_Token_Newline)
  236. {
  237. // Error.
  238. cmOStringStream error;
  239. error << "Error in cmake code at\n"
  240. << filename << ":" << cmListFileLexer_GetCurrentLine(lexer) << ":\n"
  241. << "Parse error. Function missing ending \")\". "
  242. << "Instead found "
  243. << cmListFileLexer_GetTypeAsString(lexer, token->type)
  244. << " with text \"" << token->text << "\".";
  245. cmSystemTools::Error(error.str().c_str());
  246. return false;
  247. }
  248. lastLine = cmListFileLexer_GetCurrentLine(lexer);
  249. }
  250. cmOStringStream error;
  251. error << "Error in cmake code at\n"
  252. << filename << ":" << lastLine << ":\n"
  253. << "Parse error. Function missing ending \")\". "
  254. << "End of file reached.";
  255. cmSystemTools::Error(error.str().c_str());
  256. return false;
  257. }
  258. //----------------------------------------------------------------------------
  259. const char* cmListFileCache::GetUniqueStringPointer(const char* name)
  260. {
  261. UniqueStrings::iterator i = m_UniqueStrings.find(name);
  262. if(i == m_UniqueStrings.end())
  263. {
  264. char* str = new char[strlen(name)+1];
  265. strcpy(str, name);
  266. i = m_UniqueStrings.insert(UniqueStrings::value_type(name, str)).first;
  267. }
  268. return i->second;
  269. }
  270. //----------------------------------------------------------------------------
  271. cmListFileCache::~cmListFileCache()
  272. {
  273. for(UniqueStrings::iterator i = m_UniqueStrings.begin();
  274. i != m_UniqueStrings.end(); ++i)
  275. {
  276. delete [] i->second;
  277. }
  278. }