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 "cmListCommand.h"
13 #include <cmsys/RegularExpression.hxx>
14 #include <cmsys/SystemTools.hxx>
16 #include <stdlib.h> // required for atoi
19 //----------------------------------------------------------------------------
21 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
25 this->SetError("must be called with at least two arguments.");
29 const std::string &subCommand = args[0];
30 if(subCommand == "LENGTH")
32 return this->HandleLengthCommand(args);
34 if(subCommand == "GET")
36 return this->HandleGetCommand(args);
38 if(subCommand == "APPEND")
40 return this->HandleAppendCommand(args);
42 if(subCommand == "FIND")
44 return this->HandleFindCommand(args);
46 if(subCommand == "INSERT")
48 return this->HandleInsertCommand(args);
50 if(subCommand == "REMOVE_AT")
52 return this->HandleRemoveAtCommand(args);
54 if(subCommand == "REMOVE_ITEM")
56 return this->HandleRemoveItemCommand(args);
58 if(subCommand == "REMOVE_DUPLICATES")
60 return this->HandleRemoveDuplicatesCommand(args);
62 if(subCommand == "SORT")
64 return this->HandleSortCommand(args);
66 if(subCommand == "REVERSE")
68 return this->HandleReverseCommand(args);
71 std::string e = "does not recognize sub-command "+subCommand;
72 this->SetError(e.c_str());
76 //----------------------------------------------------------------------------
77 bool cmListCommand::GetListString(std::string& listString, const char* var)
84 const char* cacheValue
85 = this->Makefile->GetDefinition(var);
90 listString = cacheValue;
94 //----------------------------------------------------------------------------
95 bool cmListCommand::GetList(std::vector<std::string>& list, const char* var)
97 std::string listString;
98 if ( !this->GetListString(listString, var) )
102 // if the size of the list
103 if(listString.size() == 0)
107 // expand the variable into a list
108 cmSystemTools::ExpandListArgument(listString, list, true);
109 // check the list for empty values
110 bool hasEmpty = false;
111 for(std::vector<std::string>::iterator i = list.begin();
112 i != list.end(); ++i)
120 // if no empty elements then just return
125 // if we have empty elements we need to check policy CMP0007
126 switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0007))
128 case cmPolicies::WARN:
130 // Default is to warn and use old behavior
131 // OLD behavior is to allow compatibility, so recall
132 // ExpandListArgument without the true which will remove
135 cmSystemTools::ExpandListArgument(listString, list);
136 std::string warn = this->Makefile->GetPolicies()->
137 GetPolicyWarning(cmPolicies::CMP0007);
138 warn += " List has value = [";
141 this->Makefile->IssueMessage(cmake::AUTHOR_WARNING,
145 case cmPolicies::OLD:
146 // OLD behavior is to allow compatibility, so recall
147 // ExpandListArgument without the true which will remove
150 cmSystemTools::ExpandListArgument(listString, list);
152 case cmPolicies::NEW:
154 case cmPolicies::REQUIRED_IF_USED:
155 case cmPolicies::REQUIRED_ALWAYS:
156 this->Makefile->IssueMessage(
158 this->Makefile->GetPolicies()
159 ->GetRequiredPolicyError(cmPolicies::CMP0007)
166 //----------------------------------------------------------------------------
167 bool cmListCommand::HandleLengthCommand(std::vector<std::string> const& args)
171 this->SetError("sub-command LENGTH requires two arguments.");
175 const std::string& listName = args[1];
176 const std::string& variableName = args[args.size() - 1];
177 std::vector<std::string> varArgsExpanded;
178 // do not check the return value here
179 // if the list var is not found varArgsExpanded will have size 0
180 // and we will return 0
181 this->GetList(varArgsExpanded, listName.c_str());
182 size_t length = varArgsExpanded.size();
184 sprintf(buffer, "%d", static_cast<int>(length));
186 this->Makefile->AddDefinition(variableName.c_str(), buffer);
190 //----------------------------------------------------------------------------
191 bool cmListCommand::HandleGetCommand(std::vector<std::string> const& args)
195 this->SetError("sub-command GET requires at least three arguments.");
199 const std::string& listName = args[1];
200 const std::string& variableName = args[args.size() - 1];
201 // expand the variable
202 std::vector<std::string> varArgsExpanded;
203 if ( !this->GetList(varArgsExpanded, listName.c_str()) )
205 this->Makefile->AddDefinition(variableName.c_str(), "NOTFOUND");
208 // FIXME: Add policy to make non-existing lists an error like empty lists.
209 if(varArgsExpanded.empty())
211 this->SetError("GET given empty list");
217 const char* sep = "";
218 for ( cc = 2; cc < args.size()-1; cc ++ )
220 int item = atoi(args[cc].c_str());
223 size_t nitem = varArgsExpanded.size();
226 item = (int)nitem + item;
228 if ( item < 0 || nitem <= (size_t)item )
231 str << "index: " << item << " out of range (-"
232 << varArgsExpanded.size() << ", "
233 << varArgsExpanded.size()-1 << ")";
234 this->SetError(str.str().c_str());
237 value += varArgsExpanded[item];
240 this->Makefile->AddDefinition(variableName.c_str(), value.c_str());
244 //----------------------------------------------------------------------------
245 bool cmListCommand::HandleAppendCommand(std::vector<std::string> const& args)
247 assert(args.size() >= 2);
249 // Skip if nothing to append.
255 const std::string& listName = args[1];
256 // expand the variable
257 std::string listString;
258 this->GetListString(listString, listName.c_str());
260 for ( cc = 2; cc < args.size(); ++ cc )
262 if(listString.size())
266 listString += args[cc];
269 this->Makefile->AddDefinition(listName.c_str(), listString.c_str());
273 //----------------------------------------------------------------------------
274 bool cmListCommand::HandleFindCommand(std::vector<std::string> const& args)
278 this->SetError("sub-command FIND requires three arguments.");
282 const std::string& listName = args[1];
283 const std::string& variableName = args[args.size() - 1];
284 // expand the variable
285 std::vector<std::string> varArgsExpanded;
286 if ( !this->GetList(varArgsExpanded, listName.c_str()) )
288 this->Makefile->AddDefinition(variableName.c_str(), "-1");
292 std::vector<std::string>::iterator it;
293 unsigned int index = 0;
294 for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it )
296 if ( *it == args[2] )
298 char indexString[32];
299 sprintf(indexString, "%d", index);
300 this->Makefile->AddDefinition(variableName.c_str(), indexString);
306 this->Makefile->AddDefinition(variableName.c_str(), "-1");
310 //----------------------------------------------------------------------------
311 bool cmListCommand::HandleInsertCommand(std::vector<std::string> const& args)
315 this->SetError("sub-command INSERT requires at least three arguments.");
319 const std::string& listName = args[1];
321 // expand the variable
322 int item = atoi(args[2].c_str());
323 std::vector<std::string> varArgsExpanded;
324 if((!this->GetList(varArgsExpanded, listName.c_str())
325 || varArgsExpanded.empty()) && item != 0)
328 str << "index: " << item << " out of range (0, 0)";
329 this->SetError(str.str().c_str());
333 if ( varArgsExpanded.size() != 0 )
335 size_t nitem = varArgsExpanded.size();
338 item = (int)nitem + item;
340 if ( item < 0 || nitem <= (size_t)item )
343 str << "index: " << item << " out of range (-"
344 << varArgsExpanded.size() << ", "
345 << (varArgsExpanded.size() == 0?0:(varArgsExpanded.size()-1)) << ")";
346 this->SetError(str.str().c_str());
352 for ( cc = 3; cc < args.size(); ++ cc )
354 varArgsExpanded.insert(varArgsExpanded.begin()+item+cnt, args[cc]);
359 const char* sep = "";
360 for ( cc = 0; cc < varArgsExpanded.size(); cc ++ )
363 value += varArgsExpanded[cc];
367 this->Makefile->AddDefinition(listName.c_str(), value.c_str());
371 //----------------------------------------------------------------------------
373 ::HandleRemoveItemCommand(std::vector<std::string> const& args)
377 this->SetError("sub-command REMOVE_ITEM requires two or more arguments.");
381 const std::string& listName = args[1];
382 // expand the variable
383 std::vector<std::string> varArgsExpanded;
384 if ( !this->GetList(varArgsExpanded, listName.c_str()) )
386 this->SetError("sub-command REMOVE_ITEM requires list to be present.");
391 for ( cc = 2; cc < args.size(); ++ cc )
394 while ( kk < varArgsExpanded.size() )
396 if ( varArgsExpanded[kk] == args[cc] )
398 varArgsExpanded.erase(varArgsExpanded.begin()+kk);
408 const char* sep = "";
409 for ( cc = 0; cc < varArgsExpanded.size(); cc ++ )
412 value += varArgsExpanded[cc];
416 this->Makefile->AddDefinition(listName.c_str(), value.c_str());
420 //----------------------------------------------------------------------------
422 ::HandleReverseCommand(std::vector<std::string> const& args)
424 assert(args.size() >= 2);
428 "sub-command REVERSE only takes one argument.");
432 const std::string& listName = args[1];
433 // expand the variable
434 std::vector<std::string> varArgsExpanded;
435 if ( !this->GetList(varArgsExpanded, listName.c_str()) )
437 this->SetError("sub-command REVERSE requires list to be present.");
442 std::vector<std::string>::reverse_iterator it;
443 const char* sep = "";
444 for ( it = varArgsExpanded.rbegin(); it != varArgsExpanded.rend(); ++ it )
447 value += it->c_str();
451 this->Makefile->AddDefinition(listName.c_str(), value.c_str());
455 //----------------------------------------------------------------------------
457 ::HandleRemoveDuplicatesCommand(std::vector<std::string> const& args)
459 assert(args.size() >= 2);
463 "sub-command REMOVE_DUPLICATES only takes one argument.");
467 const std::string& listName = args[1];
468 // expand the variable
469 std::vector<std::string> varArgsExpanded;
470 if ( !this->GetList(varArgsExpanded, listName.c_str()) )
473 "sub-command REMOVE_DUPLICATES requires list to be present.");
480 std::set<std::string> unique;
481 std::vector<std::string>::iterator it;
482 const char* sep = "";
483 for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it )
485 if (unique.find(*it) != unique.end())
491 value += it->c_str();
496 this->Makefile->AddDefinition(listName.c_str(), value.c_str());
500 //----------------------------------------------------------------------------
502 ::HandleSortCommand(std::vector<std::string> const& args)
504 assert(args.size() >= 2);
508 "sub-command SORT only takes one argument.");
512 const std::string& listName = args[1];
513 // expand the variable
514 std::vector<std::string> varArgsExpanded;
515 if ( !this->GetList(varArgsExpanded, listName.c_str()) )
517 this->SetError("sub-command SORT requires list to be present.");
521 std::sort(varArgsExpanded.begin(), varArgsExpanded.end());
524 std::vector<std::string>::iterator it;
525 const char* sep = "";
526 for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it )
529 value += it->c_str();
533 this->Makefile->AddDefinition(listName.c_str(), value.c_str());
537 //----------------------------------------------------------------------------
538 bool cmListCommand::HandleRemoveAtCommand(
539 std::vector<std::string> const& args)
543 this->SetError("sub-command REMOVE_AT requires at least "
548 const std::string& listName = args[1];
549 // expand the variable
550 std::vector<std::string> varArgsExpanded;
551 if ( !this->GetList(varArgsExpanded, listName.c_str()) )
553 this->SetError("sub-command REMOVE_AT requires list to be present.");
556 // FIXME: Add policy to make non-existing lists an error like empty lists.
557 if(varArgsExpanded.empty())
559 this->SetError("REMOVE_AT given empty list");
564 std::vector<size_t> removed;
565 for ( cc = 2; cc < args.size(); ++ cc )
567 int item = atoi(args[cc].c_str());
568 size_t nitem = varArgsExpanded.size();
571 item = (int)nitem + item;
573 if ( item < 0 || nitem <= (size_t)item )
576 str << "index: " << item << " out of range (-"
577 << varArgsExpanded.size() << ", "
578 << varArgsExpanded.size()-1 << ")";
579 this->SetError(str.str().c_str());
582 removed.push_back(static_cast<size_t>(item));
586 const char* sep = "";
587 for ( cc = 0; cc < varArgsExpanded.size(); ++ cc )
591 for ( kk = 0; kk < removed.size(); ++ kk )
593 if ( cc == removed[kk] )
602 value += varArgsExpanded[cc];
607 this->Makefile->AddDefinition(listName.c_str(), value.c_str());