1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmListFileCache.cxx,v $
6 Date: $Date: 2008-03-31 17:33:08 $
7 Version: $Revision: 1.45 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmListFileCache.h"
19 #include "cmListFileLexer.h"
20 #include "cmSystemTools.h"
21 #include "cmMakefile.h"
22 #include "cmVersion.h"
24 #include <cmsys/RegularExpression.hxx>
27 # pragma warn -8060 /* possibly incorrect assignment */
30 bool cmListFileCacheParseFunction(cmListFileLexer
* lexer
,
31 cmListFileFunction
& function
,
32 const char* filename
);
34 bool cmListFile::ParseFile(const char* filename
,
38 if(!cmSystemTools::FileExists(filename
))
43 // Create the scanner.
44 cmListFileLexer
* lexer
= cmListFileLexer_New();
47 cmSystemTools::Error("cmListFileCache: error allocating lexer ");
52 if(!cmListFileLexer_SetFileName(lexer
, filename
))
54 cmListFileLexer_Delete(lexer
);
55 cmSystemTools::Error("cmListFileCache: error can not open file ",
60 // Use a simple recursive-descent parser to process the token
62 this->ModifiedTime
= cmSystemTools::ModifiedTime(filename
);
63 bool parseError
= false;
64 bool haveNewline
= true;
65 cmListFileLexer_Token
* token
;
66 while(!parseError
&& (token
= cmListFileLexer_Scan(lexer
)))
68 if(token
->type
== cmListFileLexer_Token_Newline
)
72 else if(token
->type
== cmListFileLexer_Token_Identifier
)
77 cmListFileFunction inFunction
;
78 inFunction
.Name
= token
->text
;
79 inFunction
.FilePath
= filename
;
80 inFunction
.Line
= token
->line
;
81 if(cmListFileCacheParseFunction(lexer
, inFunction
, filename
))
83 this->Functions
.push_back(inFunction
);
92 cmOStringStream error
;
93 error
<< "Error in cmake code at\n"
94 << filename
<< ":" << token
->line
<< ":\n"
95 << "Parse error. Expected a newline, got "
96 << cmListFileLexer_GetTypeAsString(lexer
, token
->type
)
97 << " with text \"" << token
->text
<< "\".";
98 cmSystemTools::Error(error
.str().c_str());
104 cmOStringStream error
;
105 error
<< "Error in cmake code at\n"
106 << filename
<< ":" << token
->line
<< ":\n"
107 << "Parse error. Expected a command name, got "
108 << cmListFileLexer_GetTypeAsString(lexer
, token
->type
)
110 << token
->text
<< "\".";
111 cmSystemTools::Error(error
.str().c_str());
117 this->ModifiedTime
= 0;
120 cmListFileLexer_Delete(lexer
);
122 // do we need a cmake_policy(VERSION call?
125 bool hasVersion
= false;
126 // search for the right policy command
127 for(std::vector
<cmListFileFunction
>::iterator i
128 = this->Functions
.begin();
129 i
!= this->Functions
.end(); ++i
)
131 if (cmSystemTools::LowerCase(i
->Name
) == "cmake_minimum_required")
137 // if no policy command is found this is an error if they use any non advanced functions or a lot of functions
140 bool isProblem
= true;
141 if (this->Functions
.size() < 30)
143 // the list of simple commands DO NOT ADD TO THIS LIST!!!!!
144 // these commands must have backwards compatibility forever and
145 // and that is a lot longer than your tiny mind can comprehend mortal
146 std::set
<std::string
> allowedCommands
;
147 allowedCommands
.insert("project");
148 allowedCommands
.insert("set");
149 allowedCommands
.insert("if");
150 allowedCommands
.insert("endif");
151 allowedCommands
.insert("else");
152 allowedCommands
.insert("elseif");
153 allowedCommands
.insert("add_executable");
154 allowedCommands
.insert("add_library");
155 allowedCommands
.insert("target_link_libraries");
156 allowedCommands
.insert("option");
157 allowedCommands
.insert("message");
159 for(std::vector
<cmListFileFunction
>::iterator i
160 = this->Functions
.begin();
161 i
!= this->Functions
.end(); ++i
)
163 std::string name
= cmSystemTools::LowerCase(i
->Name
);
164 if (allowedCommands
.find(name
) == allowedCommands
.end())
174 // Tell the top level cmMakefile to diagnose
175 // this violation of CMP0000.
176 mf
->SetCheckCMP0000(true);
178 // Implicitly set the version for the user.
179 mf
->SetPolicyVersion("2.4");
186 bool hasProject
= false;
187 // search for a project command
188 for(std::vector
<cmListFileFunction
>::iterator i
189 = this->Functions
.begin();
190 i
!= this->Functions
.end(); ++i
)
192 if(cmSystemTools::LowerCase(i
->Name
) == "project")
198 // if no project command is found, add one
201 cmListFileFunction project
;
202 project
.Name
= "PROJECT";
203 cmListFileArgument
prj("Project", false, filename
, 0);
204 project
.Arguments
.push_back(prj
);
205 this->Functions
.insert(this->Functions
.begin(),project
);
215 bool cmListFileCacheParseFunction(cmListFileLexer
* lexer
,
216 cmListFileFunction
& function
,
217 const char* filename
)
219 // Command name has already been parsed. Read the left paren.
220 cmListFileLexer_Token
* token
;
221 if(!(token
= cmListFileLexer_Scan(lexer
)))
223 cmOStringStream error
;
224 error
<< "Error in cmake code at\n"
225 << filename
<< ":" << cmListFileLexer_GetCurrentLine(lexer
) << ":\n"
226 << "Parse error. Function missing opening \"(\".";
227 cmSystemTools::Error(error
.str().c_str());
230 if(token
->type
!= cmListFileLexer_Token_ParenLeft
)
232 cmOStringStream error
;
233 error
<< "Error in cmake code at\n"
234 << filename
<< ":" << cmListFileLexer_GetCurrentLine(lexer
) << ":\n"
235 << "Parse error. Expected \"(\", got "
236 << cmListFileLexer_GetTypeAsString(lexer
, token
->type
)
237 << " with text \"" << token
->text
<< "\".";
238 cmSystemTools::Error(error
.str().c_str());
243 unsigned long lastLine
= cmListFileLexer_GetCurrentLine(lexer
);
244 while((token
= cmListFileLexer_Scan(lexer
)))
246 if(token
->type
== cmListFileLexer_Token_ParenRight
)
250 else if(token
->type
== cmListFileLexer_Token_Identifier
||
251 token
->type
== cmListFileLexer_Token_ArgumentUnquoted
)
253 cmListFileArgument
a(token
->text
,
254 false, filename
, token
->line
);
255 function
.Arguments
.push_back(a
);
257 else if(token
->type
== cmListFileLexer_Token_ArgumentQuoted
)
259 cmListFileArgument
a(token
->text
,
260 true, filename
, token
->line
);
261 function
.Arguments
.push_back(a
);
263 else if(token
->type
!= cmListFileLexer_Token_Newline
)
266 cmOStringStream error
;
267 error
<< "Error in cmake code at\n"
268 << filename
<< ":" << cmListFileLexer_GetCurrentLine(lexer
)
270 << "Parse error. Function missing ending \")\". "
272 << cmListFileLexer_GetTypeAsString(lexer
, token
->type
)
273 << " with text \"" << token
->text
<< "\".";
274 cmSystemTools::Error(error
.str().c_str());
277 lastLine
= cmListFileLexer_GetCurrentLine(lexer
);
280 cmOStringStream error
;
281 error
<< "Error in cmake code at\n"
282 << filename
<< ":" << lastLine
<< ":\n"
283 << "Parse error. Function missing ending \")\". "
284 << "End of file reached.";
285 cmSystemTools::Error(error
.str().c_str());
290 //----------------------------------------------------------------------------
291 std::ostream
& operator<<(std::ostream
& os
, cmListFileContext
const& lfc
)
296 os
<< ":" << lfc
.Line
;
297 if(!lfc
.Name
.empty())
299 os
<< " (" << lfc
.Name
<< ")";