1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmListFileCache.cxx,v $
6 Date: $Date: 2008-06-26 17:01:35 $
7 Version: $Revision: 1.47 $
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
138 // non advanced functions or a lot of functions
141 bool isProblem
= true;
142 if (this->Functions
.size() < 30)
144 // the list of simple commands DO NOT ADD TO THIS LIST!!!!!
145 // these commands must have backwards compatibility forever and
146 // and that is a lot longer than your tiny mind can comprehend mortal
147 std::set
<std::string
> allowedCommands
;
148 allowedCommands
.insert("project");
149 allowedCommands
.insert("set");
150 allowedCommands
.insert("if");
151 allowedCommands
.insert("endif");
152 allowedCommands
.insert("else");
153 allowedCommands
.insert("elseif");
154 allowedCommands
.insert("add_executable");
155 allowedCommands
.insert("add_library");
156 allowedCommands
.insert("target_link_libraries");
157 allowedCommands
.insert("option");
158 allowedCommands
.insert("message");
160 for(std::vector
<cmListFileFunction
>::iterator i
161 = this->Functions
.begin();
162 i
!= this->Functions
.end(); ++i
)
164 std::string name
= cmSystemTools::LowerCase(i
->Name
);
165 if (allowedCommands
.find(name
) == allowedCommands
.end())
175 // Tell the top level cmMakefile to diagnose
176 // this violation of CMP0000.
177 mf
->SetCheckCMP0000(true);
179 // Implicitly set the version for the user.
180 mf
->SetPolicyVersion("2.4");
187 bool hasProject
= false;
188 // search for a project command
189 for(std::vector
<cmListFileFunction
>::iterator i
190 = this->Functions
.begin();
191 i
!= this->Functions
.end(); ++i
)
193 if(cmSystemTools::LowerCase(i
->Name
) == "project")
199 // if no project command is found, add one
202 cmListFileFunction project
;
203 project
.Name
= "PROJECT";
204 cmListFileArgument
prj("Project", false, filename
, 0);
205 project
.Arguments
.push_back(prj
);
206 this->Functions
.insert(this->Functions
.begin(),project
);
216 bool cmListFileCacheParseFunction(cmListFileLexer
* lexer
,
217 cmListFileFunction
& function
,
218 const char* filename
)
220 // Command name has already been parsed. Read the left paren.
221 cmListFileLexer_Token
* token
;
222 if(!(token
= cmListFileLexer_Scan(lexer
)))
224 cmOStringStream error
;
225 error
<< "Error in cmake code at\n"
226 << filename
<< ":" << cmListFileLexer_GetCurrentLine(lexer
) << ":\n"
227 << "Parse error. Function missing opening \"(\".";
228 cmSystemTools::Error(error
.str().c_str());
231 if(token
->type
!= cmListFileLexer_Token_ParenLeft
)
233 cmOStringStream error
;
234 error
<< "Error in cmake code at\n"
235 << filename
<< ":" << cmListFileLexer_GetCurrentLine(lexer
) << ":\n"
236 << "Parse error. Expected \"(\", got "
237 << cmListFileLexer_GetTypeAsString(lexer
, token
->type
)
238 << " with text \"" << token
->text
<< "\".";
239 cmSystemTools::Error(error
.str().c_str());
244 unsigned long lastLine
= cmListFileLexer_GetCurrentLine(lexer
);
245 unsigned long parenDepth
= 0;
246 while((token
= cmListFileLexer_Scan(lexer
)))
248 if(token
->type
== cmListFileLexer_Token_ParenLeft
)
251 cmListFileArgument
a("(",
252 false, filename
, token
->line
);
253 function
.Arguments
.push_back(a
);
255 else if(token
->type
== cmListFileLexer_Token_ParenRight
)
262 cmListFileArgument
a(")",
263 false, filename
, token
->line
);
264 function
.Arguments
.push_back(a
);
266 else if(token
->type
== cmListFileLexer_Token_Identifier
||
267 token
->type
== cmListFileLexer_Token_ArgumentUnquoted
)
269 cmListFileArgument
a(token
->text
,
270 false, filename
, token
->line
);
271 function
.Arguments
.push_back(a
);
273 else if(token
->type
== cmListFileLexer_Token_ArgumentQuoted
)
275 cmListFileArgument
a(token
->text
,
276 true, filename
, token
->line
);
277 function
.Arguments
.push_back(a
);
279 else if(token
->type
!= cmListFileLexer_Token_Newline
)
282 cmOStringStream error
;
283 error
<< "Error in cmake code at\n"
284 << filename
<< ":" << cmListFileLexer_GetCurrentLine(lexer
)
286 << "Parse error. Function missing ending \")\". "
288 << cmListFileLexer_GetTypeAsString(lexer
, token
->type
)
289 << " with text \"" << token
->text
<< "\".";
290 cmSystemTools::Error(error
.str().c_str());
293 lastLine
= cmListFileLexer_GetCurrentLine(lexer
);
296 cmOStringStream error
;
297 error
<< "Error in cmake code at\n"
298 << filename
<< ":" << lastLine
<< ":\n"
299 << "Parse error. Function missing ending \")\". "
300 << "End of file reached.";
301 cmSystemTools::Error(error
.str().c_str());
306 //----------------------------------------------------------------------------
307 std::ostream
& operator<<(std::ostream
& os
, cmListFileContext
const& lfc
)
312 os
<< ":" << lfc
.Line
;
313 if(!lfc
.Name
.empty())
315 os
<< " (" << lfc
.Name
<< ")";