1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
12 #include "cmListFileCache.h"
14 #include "cmListFileLexer.h"
15 #include "cmSystemTools.h"
16 #include "cmMakefile.h"
17 #include "cmVersion.h"
19 #include <cmsys/RegularExpression.hxx>
22 # pragma warn -8060 /* possibly incorrect assignment */
25 bool cmListFileCacheParseFunction(cmListFileLexer* lexer,
26 cmListFileFunction& function,
27 const char* filename);
29 bool cmListFile::ParseFile(const char* filename,
33 if(!cmSystemTools::FileExists(filename))
38 // Create the scanner.
39 cmListFileLexer* lexer = cmListFileLexer_New();
42 cmSystemTools::Error("cmListFileCache: error allocating lexer ");
47 if(!cmListFileLexer_SetFileName(lexer, filename))
49 cmListFileLexer_Delete(lexer);
50 cmSystemTools::Error("cmListFileCache: error can not open file ",
55 // Use a simple recursive-descent parser to process the token
57 this->ModifiedTime = cmSystemTools::ModifiedTime(filename);
58 bool parseError = false;
59 bool haveNewline = true;
60 cmListFileLexer_Token* token;
61 while(!parseError && (token = cmListFileLexer_Scan(lexer)))
63 if(token->type == cmListFileLexer_Token_Newline)
67 else if(token->type == cmListFileLexer_Token_Identifier)
72 cmListFileFunction inFunction;
73 inFunction.Name = token->text;
74 inFunction.FilePath = filename;
75 inFunction.Line = token->line;
76 if(cmListFileCacheParseFunction(lexer, inFunction, filename))
78 this->Functions.push_back(inFunction);
87 cmOStringStream error;
88 error << "Error in cmake code at\n"
89 << filename << ":" << token->line << ":\n"
90 << "Parse error. Expected a newline, got "
91 << cmListFileLexer_GetTypeAsString(lexer, token->type)
92 << " with text \"" << token->text << "\".";
93 cmSystemTools::Error(error.str().c_str());
99 cmOStringStream error;
100 error << "Error in cmake code at\n"
101 << filename << ":" << token->line << ":\n"
102 << "Parse error. Expected a command name, got "
103 << cmListFileLexer_GetTypeAsString(lexer, token->type)
105 << token->text << "\".";
106 cmSystemTools::Error(error.str().c_str());
112 this->ModifiedTime = 0;
115 cmListFileLexer_Delete(lexer);
117 // do we need a cmake_policy(VERSION call?
120 bool hasVersion = false;
121 // search for the right policy command
122 for(std::vector<cmListFileFunction>::iterator i
123 = this->Functions.begin();
124 i != this->Functions.end(); ++i)
126 if (cmSystemTools::LowerCase(i->Name) == "cmake_minimum_required")
132 // if no policy command is found this is an error if they use any
133 // non advanced functions or a lot of functions
136 bool isProblem = true;
137 if (this->Functions.size() < 30)
139 // the list of simple commands DO NOT ADD TO THIS LIST!!!!!
140 // these commands must have backwards compatibility forever and
141 // and that is a lot longer than your tiny mind can comprehend mortal
142 std::set<std::string> allowedCommands;
143 allowedCommands.insert("project");
144 allowedCommands.insert("set");
145 allowedCommands.insert("if");
146 allowedCommands.insert("endif");
147 allowedCommands.insert("else");
148 allowedCommands.insert("elseif");
149 allowedCommands.insert("add_executable");
150 allowedCommands.insert("add_library");
151 allowedCommands.insert("target_link_libraries");
152 allowedCommands.insert("option");
153 allowedCommands.insert("message");
155 for(std::vector<cmListFileFunction>::iterator i
156 = this->Functions.begin();
157 i != this->Functions.end(); ++i)
159 std::string name = cmSystemTools::LowerCase(i->Name);
160 if (allowedCommands.find(name) == allowedCommands.end())
170 // Tell the top level cmMakefile to diagnose
171 // this violation of CMP0000.
172 mf->SetCheckCMP0000(true);
174 // Implicitly set the version for the user.
175 mf->SetPolicyVersion("2.4");
182 bool hasProject = false;
183 // search for a project command
184 for(std::vector<cmListFileFunction>::iterator i
185 = this->Functions.begin();
186 i != this->Functions.end(); ++i)
188 if(cmSystemTools::LowerCase(i->Name) == "project")
194 // if no project command is found, add one
197 cmListFileFunction project;
198 project.Name = "PROJECT";
199 cmListFileArgument prj("Project", false, filename, 0);
200 project.Arguments.push_back(prj);
201 this->Functions.insert(this->Functions.begin(),project);
211 bool cmListFileCacheParseFunction(cmListFileLexer* lexer,
212 cmListFileFunction& function,
213 const char* filename)
215 // Command name has already been parsed. Read the left paren.
216 cmListFileLexer_Token* token;
217 if(!(token = cmListFileLexer_Scan(lexer)))
219 cmOStringStream error;
220 error << "Error in cmake code at\n"
221 << filename << ":" << cmListFileLexer_GetCurrentLine(lexer) << ":\n"
222 << "Parse error. Function missing opening \"(\".";
223 cmSystemTools::Error(error.str().c_str());
226 if(token->type != cmListFileLexer_Token_ParenLeft)
228 cmOStringStream error;
229 error << "Error in cmake code at\n"
230 << filename << ":" << cmListFileLexer_GetCurrentLine(lexer) << ":\n"
231 << "Parse error. Expected \"(\", got "
232 << cmListFileLexer_GetTypeAsString(lexer, token->type)
233 << " with text \"" << token->text << "\".";
234 cmSystemTools::Error(error.str().c_str());
239 unsigned long lastLine = cmListFileLexer_GetCurrentLine(lexer);
240 unsigned long parenDepth = 0;
241 while((token = cmListFileLexer_Scan(lexer)))
243 if(token->type == cmListFileLexer_Token_ParenLeft)
246 cmListFileArgument a("(",
247 false, filename, token->line);
248 function.Arguments.push_back(a);
250 else if(token->type == cmListFileLexer_Token_ParenRight)
257 cmListFileArgument a(")",
258 false, filename, token->line);
259 function.Arguments.push_back(a);
261 else if(token->type == cmListFileLexer_Token_Identifier ||
262 token->type == cmListFileLexer_Token_ArgumentUnquoted)
264 cmListFileArgument a(token->text,
265 false, filename, token->line);
266 function.Arguments.push_back(a);
268 else if(token->type == cmListFileLexer_Token_ArgumentQuoted)
270 cmListFileArgument a(token->text,
271 true, filename, token->line);
272 function.Arguments.push_back(a);
274 else if(token->type != cmListFileLexer_Token_Newline)
277 cmOStringStream error;
278 error << "Error in cmake code at\n"
279 << filename << ":" << cmListFileLexer_GetCurrentLine(lexer)
281 << "Parse error. Function missing ending \")\". "
283 << cmListFileLexer_GetTypeAsString(lexer, token->type)
284 << " with text \"" << token->text << "\".";
285 cmSystemTools::Error(error.str().c_str());
288 lastLine = cmListFileLexer_GetCurrentLine(lexer);
291 cmOStringStream error;
292 error << "Error in cmake code at\n"
293 << filename << ":" << lastLine << ":\n"
294 << "Parse error. Function missing ending \")\". "
295 << "End of file reached.";
296 cmSystemTools::Error(error.str().c_str());
301 //----------------------------------------------------------------------------
302 std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc)
307 os << ":" << lfc.Line;
308 if(!lfc.Name.empty())
310 os << " (" << lfc.Name << ")";