1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmListCommand.cxx,v $
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
23 //----------------------------------------------------------------------------
25 ::InitialPass(std::vector
<std::string
> const& args
, cmExecutionStatus
&)
29 this->SetError("must be called with at least one argument.");
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());
80 //----------------------------------------------------------------------------
81 bool cmListCommand::GetListString(std::string
& listString
, const char* var
)
88 const char* cacheValue
89 = this->Makefile
->GetDefinition(var
);
94 listString
= cacheValue
;
98 //----------------------------------------------------------------------------
99 bool cmListCommand::GetList(std::vector
<std::string
>& list
, const char* var
)
101 std::string listString
;
102 if ( !this->GetListString(listString
, var
) )
106 // if the size of the list
107 if(listString
.size() == 0)
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
)
124 // if no empty elements then just return
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
139 cmSystemTools::ExpandListArgument(listString
, list
);
140 std::string warn
= this->Makefile
->GetPolicies()->
141 GetPolicyWarning(cmPolicies::CMP0007
);
142 warn
+= " List has value = [";
145 this->Makefile
->IssueMessage(cmake::AUTHOR_WARNING
,
149 case cmPolicies::OLD
:
150 // OLD behavior is to allow compatibility, so recall
151 // ExpandListArgument without the true which will remove
154 cmSystemTools::ExpandListArgument(listString
, list
);
156 case cmPolicies::NEW
:
158 case cmPolicies::REQUIRED_IF_USED
:
159 case cmPolicies::REQUIRED_ALWAYS
:
160 this->Makefile
->IssueMessage(
162 this->Makefile
->GetPolicies()
163 ->GetRequiredPolicyError(cmPolicies::CMP0007
)
170 //----------------------------------------------------------------------------
171 bool cmListCommand::HandleLengthCommand(std::vector
<std::string
> const& args
)
175 this->SetError("sub-command LENGTH requires two arguments.");
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();
188 sprintf(buffer
, "%d", static_cast<int>(length
));
190 this->Makefile
->AddDefinition(variableName
.c_str(), buffer
);
194 //----------------------------------------------------------------------------
195 bool cmListCommand::HandleGetCommand(std::vector
<std::string
> const& args
)
199 this->SetError("sub-command GET requires at least three arguments.");
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");
215 const char* sep
= "";
216 for ( cc
= 2; cc
< args
.size()-1; cc
++ )
218 int item
= atoi(args
[cc
].c_str());
221 size_t nitem
= varArgsExpanded
.size();
224 item
= (int)nitem
+ item
;
226 if ( item
< 0 || nitem
<= (size_t)item
)
229 str
<< "index: " << item
<< " out of range (-"
230 << varArgsExpanded
.size() << ", "
231 << varArgsExpanded
.size()-1 << ")";
232 this->SetError(str
.str().c_str());
235 value
+= varArgsExpanded
[item
];
238 this->Makefile
->AddDefinition(variableName
.c_str(), value
.c_str());
242 //----------------------------------------------------------------------------
243 bool cmListCommand::HandleAppendCommand(std::vector
<std::string
> const& args
)
247 this->SetError("sub-command APPEND requires at least one argument.");
251 // Skip if nothing to append.
257 const std::string
& listName
= args
[1];
258 // expand the variable
259 std::string listString
;
260 this->GetListString(listString
, listName
.c_str());
262 for ( cc
= 2; cc
< args
.size(); ++ cc
)
264 if(listString
.size())
268 listString
+= args
[cc
];
271 this->Makefile
->AddDefinition(listName
.c_str(), listString
.c_str());
275 //----------------------------------------------------------------------------
276 bool cmListCommand::HandleFindCommand(std::vector
<std::string
> const& args
)
280 this->SetError("sub-command FIND requires three arguments.");
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");
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
);
308 this->Makefile
->AddDefinition(variableName
.c_str(), "-1");
312 //----------------------------------------------------------------------------
313 bool cmListCommand::HandleInsertCommand(std::vector
<std::string
> const& args
)
317 this->SetError("sub-command INSERT requires at least three arguments.");
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)
329 str
<< "index: " << item
<< " out of range (0, 0)";
330 this->SetError(str
.str().c_str());
334 if ( varArgsExpanded
.size() != 0 )
336 size_t nitem
= varArgsExpanded
.size();
339 item
= (int)nitem
+ item
;
341 if ( item
< 0 || nitem
<= (size_t)item
)
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());
353 for ( cc
= 3; cc
< args
.size(); ++ cc
)
355 varArgsExpanded
.insert(varArgsExpanded
.begin()+item
+cnt
, args
[cc
]);
360 const char* sep
= "";
361 for ( cc
= 0; cc
< varArgsExpanded
.size(); cc
++ )
364 value
+= varArgsExpanded
[cc
];
368 this->Makefile
->AddDefinition(listName
.c_str(), value
.c_str());
372 //----------------------------------------------------------------------------
374 ::HandleRemoveItemCommand(std::vector
<std::string
> const& args
)
378 this->SetError("sub-command REMOVE_ITEM requires two or more arguments.");
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.");
392 for ( cc
= 2; cc
< args
.size(); ++ cc
)
395 while ( kk
< varArgsExpanded
.size() )
397 if ( varArgsExpanded
[kk
] == args
[cc
] )
399 varArgsExpanded
.erase(varArgsExpanded
.begin()+kk
);
409 const char* sep
= "";
410 for ( cc
= 0; cc
< varArgsExpanded
.size(); cc
++ )
413 value
+= varArgsExpanded
[cc
];
417 this->Makefile
->AddDefinition(listName
.c_str(), value
.c_str());
421 //----------------------------------------------------------------------------
423 ::HandleReverseCommand(std::vector
<std::string
> const& args
)
427 this->SetError("sub-command REVERSE requires a list as an argument.");
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.");
441 std::vector
<std::string
>::reverse_iterator it
;
442 const char* sep
= "";
443 for ( it
= varArgsExpanded
.rbegin(); it
!= varArgsExpanded
.rend(); ++ it
)
446 value
+= it
->c_str();
450 this->Makefile
->AddDefinition(listName
.c_str(), value
.c_str());
454 //----------------------------------------------------------------------------
456 ::HandleRemoveDuplicatesCommand(std::vector
<std::string
> const& args
)
461 "sub-command REMOVE_DUPLICATES requires a list as an argument.");
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()) )
471 "sub-command REMOVE_DUPLICATES requires list to be present.");
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())
489 value
+= it
->c_str();
494 this->Makefile
->AddDefinition(listName
.c_str(), value
.c_str());
498 //----------------------------------------------------------------------------
500 ::HandleSortCommand(std::vector
<std::string
> const& args
)
504 this->SetError("sub-command SORT requires a list as an argument.");
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.");
517 std::sort(varArgsExpanded
.begin(), varArgsExpanded
.end());
520 std::vector
<std::string
>::iterator it
;
521 const char* sep
= "";
522 for ( it
= varArgsExpanded
.begin(); it
!= varArgsExpanded
.end(); ++ it
)
525 value
+= it
->c_str();
529 this->Makefile
->AddDefinition(listName
.c_str(), value
.c_str());
533 //----------------------------------------------------------------------------
534 bool cmListCommand::HandleRemoveAtCommand(
535 std::vector
<std::string
> const& args
)
539 this->SetError("sub-command REMOVE_AT requires at least "
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.");
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();
561 item
= (int)nitem
+ item
;
563 if ( item
< 0 || nitem
<= (size_t)item
)
566 str
<< "index: " << item
<< " out of range (-"
567 << varArgsExpanded
.size() << ", "
568 << varArgsExpanded
.size()-1 << ")";
569 this->SetError(str
.str().c_str());
572 removed
.push_back(static_cast<size_t>(item
));
576 const char* sep
= "";
577 for ( cc
= 0; cc
< varArgsExpanded
.size(); ++ cc
)
581 for ( kk
= 0; kk
< removed
.size(); ++ kk
)
583 if ( cc
== removed
[kk
] )
592 value
+= varArgsExpanded
[cc
];
597 this->Makefile
->AddDefinition(listName
.c_str(), value
.c_str());