BUG: Fix find_* search order with path suffixes
[cmake.git] / Source / cmListCommand.cxx
blob555818e6dcf0f61b73abbfaed0e2ba5443547eb0
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmListCommand.cxx,v $
5 Language: C++
6 Date: $Date: 2008-05-20 16:15:40 $
7 Version: $Revision: 1.24 $
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 "cmListCommand.h"
18 #include <cmsys/RegularExpression.hxx>
19 #include <cmsys/SystemTools.hxx>
21 #include <stdlib.h> // required for atoi
22 #include <ctype.h>
23 //----------------------------------------------------------------------------
24 bool cmListCommand
25 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
27 if(args.size() < 1)
29 this->SetError("must be called with at least one argument.");
30 return false;
33 const std::string &subCommand = args[0];
34 if(subCommand == "LENGTH")
36 return this->HandleLengthCommand(args);
38 if(subCommand == "GET")
40 return this->HandleGetCommand(args);
42 if(subCommand == "APPEND")
44 return this->HandleAppendCommand(args);
46 if(subCommand == "FIND")
48 return this->HandleFindCommand(args);
50 if(subCommand == "INSERT")
52 return this->HandleInsertCommand(args);
54 if(subCommand == "REMOVE_AT")
56 return this->HandleRemoveAtCommand(args);
58 if(subCommand == "REMOVE_ITEM")
60 return this->HandleRemoveItemCommand(args);
62 if(subCommand == "REMOVE_DUPLICATES")
64 return this->HandleRemoveDuplicatesCommand(args);
66 if(subCommand == "SORT")
68 return this->HandleSortCommand(args);
70 if(subCommand == "REVERSE")
72 return this->HandleReverseCommand(args);
75 std::string e = "does not recognize sub-command "+subCommand;
76 this->SetError(e.c_str());
77 return false;
80 //----------------------------------------------------------------------------
81 bool cmListCommand::GetListString(std::string& listString, const char* var)
83 if ( !var )
85 return false;
87 // get the old value
88 const char* cacheValue
89 = this->Makefile->GetDefinition(var);
90 if(!cacheValue)
92 return false;
94 listString = cacheValue;
95 return true;
98 //----------------------------------------------------------------------------
99 bool cmListCommand::GetList(std::vector<std::string>& list, const char* var)
101 std::string listString;
102 if ( !this->GetListString(listString, var) )
104 return false;
106 // if the size of the list
107 if(listString.size() == 0)
109 return true;
111 // expand the variable into a list
112 cmSystemTools::ExpandListArgument(listString, list, true);
113 // check the list for empty values
114 bool hasEmpty = false;
115 for(std::vector<std::string>::iterator i = list.begin();
116 i != list.end(); ++i)
118 if(i->size() == 0)
120 hasEmpty = true;
121 break;
124 // if no empty elements then just return
125 if(!hasEmpty)
127 return true;
129 // if we have empty elements we need to check policy CMP0007
130 switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0007))
132 case cmPolicies::WARN:
134 // Default is to warn and use old behavior
135 // OLD behavior is to allow compatibility, so recall
136 // ExpandListArgument without the true which will remove
137 // empty values
138 list.clear();
139 cmSystemTools::ExpandListArgument(listString, list);
140 std::string warn = this->Makefile->GetPolicies()->
141 GetPolicyWarning(cmPolicies::CMP0007);
142 warn += " List has value = [";
143 warn += listString;
144 warn += "].";
145 this->Makefile->IssueMessage(cmake::AUTHOR_WARNING,
146 warn);
147 return true;
149 case cmPolicies::OLD:
150 // OLD behavior is to allow compatibility, so recall
151 // ExpandListArgument without the true which will remove
152 // empty values
153 list.clear();
154 cmSystemTools::ExpandListArgument(listString, list);
155 return true;
156 case cmPolicies::NEW:
157 return true;
158 case cmPolicies::REQUIRED_IF_USED:
159 case cmPolicies::REQUIRED_ALWAYS:
160 this->Makefile->IssueMessage(
161 cmake::FATAL_ERROR,
162 this->Makefile->GetPolicies()
163 ->GetRequiredPolicyError(cmPolicies::CMP0007)
165 return false;
167 return true;
170 //----------------------------------------------------------------------------
171 bool cmListCommand::HandleLengthCommand(std::vector<std::string> const& args)
173 if(args.size() != 3)
175 this->SetError("sub-command LENGTH requires two arguments.");
176 return false;
179 const std::string& listName = args[1];
180 const std::string& variableName = args[args.size() - 1];
181 std::vector<std::string> varArgsExpanded;
182 // do not check the return value here
183 // if the list var is not found varArgsExpanded will have size 0
184 // and we will return 0
185 this->GetList(varArgsExpanded, listName.c_str());
186 size_t length = varArgsExpanded.size();
187 char buffer[1024];
188 sprintf(buffer, "%d", static_cast<int>(length));
190 this->Makefile->AddDefinition(variableName.c_str(), buffer);
191 return true;
194 //----------------------------------------------------------------------------
195 bool cmListCommand::HandleGetCommand(std::vector<std::string> const& args)
197 if(args.size() < 4)
199 this->SetError("sub-command GET requires at least three arguments.");
200 return false;
203 const std::string& listName = args[1];
204 const std::string& variableName = args[args.size() - 1];
205 // expand the variable
206 std::vector<std::string> varArgsExpanded;
207 if ( !this->GetList(varArgsExpanded, listName.c_str()) )
209 this->Makefile->AddDefinition(variableName.c_str(), "NOTFOUND");
210 return true;
213 std::string value;
214 size_t cc;
215 const char* sep = "";
216 for ( cc = 2; cc < args.size()-1; cc ++ )
218 int item = atoi(args[cc].c_str());
219 value += sep;
220 sep = ";";
221 size_t nitem = varArgsExpanded.size();
222 if ( item < 0 )
224 item = (int)nitem + item;
226 if ( item < 0 || nitem <= (size_t)item )
228 cmOStringStream str;
229 str << "index: " << item << " out of range (-"
230 << varArgsExpanded.size() << ", "
231 << varArgsExpanded.size()-1 << ")";
232 this->SetError(str.str().c_str());
233 return false;
235 value += varArgsExpanded[item];
238 this->Makefile->AddDefinition(variableName.c_str(), value.c_str());
239 return true;
242 //----------------------------------------------------------------------------
243 bool cmListCommand::HandleAppendCommand(std::vector<std::string> const& args)
245 if(args.size() < 2)
247 this->SetError("sub-command APPEND requires at least one argument.");
248 return false;
251 // Skip if nothing to append.
252 if(args.size() < 3)
254 return true;
257 const std::string& listName = args[1];
258 // expand the variable
259 std::string listString;
260 this->GetListString(listString, listName.c_str());
261 size_t cc;
262 for ( cc = 2; cc < args.size(); ++ cc )
264 if(listString.size())
266 listString += ";";
268 listString += args[cc];
271 this->Makefile->AddDefinition(listName.c_str(), listString.c_str());
272 return true;
275 //----------------------------------------------------------------------------
276 bool cmListCommand::HandleFindCommand(std::vector<std::string> const& args)
278 if(args.size() != 4)
280 this->SetError("sub-command FIND requires three arguments.");
281 return false;
284 const std::string& listName = args[1];
285 const std::string& variableName = args[args.size() - 1];
286 // expand the variable
287 std::vector<std::string> varArgsExpanded;
288 if ( !this->GetList(varArgsExpanded, listName.c_str()) )
290 this->Makefile->AddDefinition(variableName.c_str(), "-1");
291 return true;
294 std::vector<std::string>::iterator it;
295 unsigned int index = 0;
296 for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it )
298 if ( *it == args[2] )
300 char indexString[32];
301 sprintf(indexString, "%d", index);
302 this->Makefile->AddDefinition(variableName.c_str(), indexString);
303 return true;
305 index++;
308 this->Makefile->AddDefinition(variableName.c_str(), "-1");
309 return true;
312 //----------------------------------------------------------------------------
313 bool cmListCommand::HandleInsertCommand(std::vector<std::string> const& args)
315 if(args.size() < 4)
317 this->SetError("sub-command INSERT requires at least three arguments.");
318 return false;
321 const std::string& listName = args[1];
323 // expand the variable
324 int item = atoi(args[2].c_str());
325 std::vector<std::string> varArgsExpanded;
326 if ( !this->GetList(varArgsExpanded, listName.c_str()) && item != 0)
328 cmOStringStream str;
329 str << "index: " << item << " out of range (0, 0)";
330 this->SetError(str.str().c_str());
331 return false;
334 if ( varArgsExpanded.size() != 0 )
336 size_t nitem = varArgsExpanded.size();
337 if ( item < 0 )
339 item = (int)nitem + item;
341 if ( item < 0 || nitem <= (size_t)item )
343 cmOStringStream str;
344 str << "index: " << item << " out of range (-"
345 << varArgsExpanded.size() << ", "
346 << (varArgsExpanded.size() == 0?0:(varArgsExpanded.size()-1)) << ")";
347 this->SetError(str.str().c_str());
348 return false;
351 size_t cc;
352 size_t cnt = 0;
353 for ( cc = 3; cc < args.size(); ++ cc )
355 varArgsExpanded.insert(varArgsExpanded.begin()+item+cnt, args[cc]);
356 cnt ++;
359 std::string value;
360 const char* sep = "";
361 for ( cc = 0; cc < varArgsExpanded.size(); cc ++ )
363 value += sep;
364 value += varArgsExpanded[cc];
365 sep = ";";
368 this->Makefile->AddDefinition(listName.c_str(), value.c_str());
369 return true;
372 //----------------------------------------------------------------------------
373 bool cmListCommand
374 ::HandleRemoveItemCommand(std::vector<std::string> const& args)
376 if(args.size() < 3)
378 this->SetError("sub-command REMOVE_ITEM requires two or more arguments.");
379 return false;
382 const std::string& listName = args[1];
383 // expand the variable
384 std::vector<std::string> varArgsExpanded;
385 if ( !this->GetList(varArgsExpanded, listName.c_str()) )
387 this->SetError("sub-command REMOVE_ITEM requires list to be present.");
388 return false;
391 size_t cc;
392 for ( cc = 2; cc < args.size(); ++ cc )
394 size_t kk = 0;
395 while ( kk < varArgsExpanded.size() )
397 if ( varArgsExpanded[kk] == args[cc] )
399 varArgsExpanded.erase(varArgsExpanded.begin()+kk);
401 else
403 kk ++;
408 std::string value;
409 const char* sep = "";
410 for ( cc = 0; cc < varArgsExpanded.size(); cc ++ )
412 value += sep;
413 value += varArgsExpanded[cc];
414 sep = ";";
417 this->Makefile->AddDefinition(listName.c_str(), value.c_str());
418 return true;
421 //----------------------------------------------------------------------------
422 bool cmListCommand
423 ::HandleReverseCommand(std::vector<std::string> const& args)
425 if(args.size() < 2)
427 this->SetError("sub-command REVERSE requires a list as an argument.");
428 return false;
431 const std::string& listName = args[1];
432 // expand the variable
433 std::vector<std::string> varArgsExpanded;
434 if ( !this->GetList(varArgsExpanded, listName.c_str()) )
436 this->SetError("sub-command REVERSE requires list to be present.");
437 return false;
440 std::string value;
441 std::vector<std::string>::reverse_iterator it;
442 const char* sep = "";
443 for ( it = varArgsExpanded.rbegin(); it != varArgsExpanded.rend(); ++ it )
445 value += sep;
446 value += it->c_str();
447 sep = ";";
450 this->Makefile->AddDefinition(listName.c_str(), value.c_str());
451 return true;
454 //----------------------------------------------------------------------------
455 bool cmListCommand
456 ::HandleRemoveDuplicatesCommand(std::vector<std::string> const& args)
458 if(args.size() < 2)
460 this->SetError(
461 "sub-command REMOVE_DUPLICATES requires a list as an argument.");
462 return false;
465 const std::string& listName = args[1];
466 // expand the variable
467 std::vector<std::string> varArgsExpanded;
468 if ( !this->GetList(varArgsExpanded, listName.c_str()) )
470 this->SetError(
471 "sub-command REMOVE_DUPLICATES requires list to be present.");
472 return false;
475 std::string value;
478 std::set<std::string> unique;
479 std::vector<std::string>::iterator it;
480 const char* sep = "";
481 for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it )
483 if (unique.find(*it) != unique.end())
485 continue;
487 unique.insert(*it);
488 value += sep;
489 value += it->c_str();
490 sep = ";";
494 this->Makefile->AddDefinition(listName.c_str(), value.c_str());
495 return true;
498 //----------------------------------------------------------------------------
499 bool cmListCommand
500 ::HandleSortCommand(std::vector<std::string> const& args)
502 if(args.size() < 2)
504 this->SetError("sub-command SORT requires a list as an argument.");
505 return false;
508 const std::string& listName = args[1];
509 // expand the variable
510 std::vector<std::string> varArgsExpanded;
511 if ( !this->GetList(varArgsExpanded, listName.c_str()) )
513 this->SetError("sub-command SORT requires list to be present.");
514 return false;
517 std::sort(varArgsExpanded.begin(), varArgsExpanded.end());
519 std::string value;
520 std::vector<std::string>::iterator it;
521 const char* sep = "";
522 for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it )
524 value += sep;
525 value += it->c_str();
526 sep = ";";
529 this->Makefile->AddDefinition(listName.c_str(), value.c_str());
530 return true;
533 //----------------------------------------------------------------------------
534 bool cmListCommand::HandleRemoveAtCommand(
535 std::vector<std::string> const& args)
537 if(args.size() < 3)
539 this->SetError("sub-command REMOVE_AT requires at least "
540 "two arguments.");
541 return false;
544 const std::string& listName = args[1];
545 // expand the variable
546 std::vector<std::string> varArgsExpanded;
547 if ( !this->GetList(varArgsExpanded, listName.c_str()) )
549 this->SetError("sub-command REMOVE_AT requires list to be present.");
550 return false;
553 size_t cc;
554 std::vector<size_t> removed;
555 for ( cc = 2; cc < args.size(); ++ cc )
557 int item = atoi(args[cc].c_str());
558 size_t nitem = varArgsExpanded.size();
559 if ( item < 0 )
561 item = (int)nitem + item;
563 if ( item < 0 || nitem <= (size_t)item )
565 cmOStringStream str;
566 str << "index: " << item << " out of range (-"
567 << varArgsExpanded.size() << ", "
568 << varArgsExpanded.size()-1 << ")";
569 this->SetError(str.str().c_str());
570 return false;
572 removed.push_back(static_cast<size_t>(item));
575 std::string value;
576 const char* sep = "";
577 for ( cc = 0; cc < varArgsExpanded.size(); ++ cc )
579 size_t kk;
580 bool found = false;
581 for ( kk = 0; kk < removed.size(); ++ kk )
583 if ( cc == removed[kk] )
585 found = true;
589 if ( !found )
591 value += sep;
592 value += varArgsExpanded[cc];
593 sep = ";";
597 this->Makefile->AddDefinition(listName.c_str(), value.c_str());
598 return true;