ENH: Add initial implementation of the list command

This commit is contained in:
Andy Cedilnik 2006-02-10 14:11:12 -05:00
parent b8a33fb424
commit f87271d0ea
6 changed files with 521 additions and 1 deletions

View File

@ -121,7 +121,7 @@ IF(BUILD_CursesDialog)
SUBDIRS(Source/CursesDialog/form)
ENDIF(BUILD_CursesDialog)
SUBDIRS(Source Modules Templates Utilities)
SUBDIRS(Source Modules Templates Utilities Tests/CMakeTests)
ENABLE_TESTING()
# Include the standard Dart testing module

View File

@ -28,6 +28,7 @@
#include "cmIncludeExternalMSProjectCommand.cxx"
#include "cmInstallCommand.cxx"
#include "cmLinkLibrariesCommand.cxx"
#include "cmListCommand.cxx"
#include "cmLoadCacheCommand.cxx"
#include "cmMathCommand.cxx"
#include "cmOutputRequiredFilesCommand.cxx"
@ -71,6 +72,7 @@ void GetPredefinedCommands(std::list<cmCommand*>&
commands.push_back(new cmIncludeExternalMSProjectCommand);
commands.push_back(new cmInstallCommand);
commands.push_back(new cmLinkLibrariesCommand);
commands.push_back(new cmListCommand);
commands.push_back(new cmLoadCacheCommand);
commands.push_back(new cmLoadCommandCommand);
commands.push_back(new cmMathCommand);

359
Source/cmListCommand.cxx Normal file
View File

@ -0,0 +1,359 @@
/*=========================================================================
Program: CMake - Cross-Platform Makefile Generator
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#include "cmListCommand.h"
#include <cmsys/RegularExpression.hxx>
#include <cmsys/SystemTools.hxx>
#include <stdlib.h> // required for atoi
#include <ctype.h>
//----------------------------------------------------------------------------
bool cmListCommand::InitialPass(std::vector<std::string> const& args)
{
if(args.size() < 1)
{
this->SetError("must be called with at least one argument.");
return false;
}
const std::string &subCommand = args[0];
if(subCommand == "LENGTH")
{
return this->HandleLengthCommand(args);
}
if(subCommand == "GET")
{
return this->HandleGetCommand(args);
}
if(subCommand == "SET")
{
return this->HandleSetCommand(args);
}
if(subCommand == "INSERT")
{
return this->HandleInsertCommand(args);
}
if(subCommand == "REMOVE")
{
return this->HandleRemoveCommand(args);
}
if(subCommand == "REMOVE_ITEM")
{
return this->HandleRemoveItemCommand(args);
}
std::string e = "does not recognize sub-command "+subCommand;
this->SetError(e.c_str());
return false;
}
//----------------------------------------------------------------------------
bool cmListCommand::GetListString(std::string& listString, const char* var)
{
if ( !var )
{
return false;
}
// get the old value
const char* cacheValue
= m_Makefile->GetDefinition(var);
if(!cacheValue)
{
cmOStringStream str;
str << "cannot find variable: " << var;
this->SetError(str.str().c_str());
return false;
}
listString = cacheValue;
return true;
}
//----------------------------------------------------------------------------
bool cmListCommand::GetList(std::vector<std::string>& list, const char* var)
{
std::string listString;
if ( !this->GetListString(listString, var) )
{
return false;
}
// expand the variable
cmSystemTools::ExpandListArgument(listString, list);
return true;
}
//----------------------------------------------------------------------------
bool cmListCommand::HandleLengthCommand(std::vector<std::string> const& args)
{
if(args.size() != 3)
{
this->SetError("sub-command LENGTH requires two arguments.");
return false;
}
const std::string& listName = args[1];
const std::string& variableName = args[args.size() - 1];
std::vector<std::string> varArgsExpanded;
if ( !this->GetList(varArgsExpanded, listName.c_str()) )
{
return false;
}
size_t length = varArgsExpanded.size();
char buffer[1024];
sprintf(buffer, "%d", static_cast<int>(length));
m_Makefile->AddDefinition(variableName.c_str(), buffer);
return true;
}
//----------------------------------------------------------------------------
bool cmListCommand::HandleGetCommand(std::vector<std::string> const& args)
{
if(args.size() < 4)
{
this->SetError("sub-command GET requires at least three arguments.");
return false;
}
const std::string& listName = args[1];
const std::string& variableName = args[args.size() - 1];
// expand the variable
std::vector<std::string> varArgsExpanded;
if ( !this->GetList(varArgsExpanded, listName.c_str()) )
{
return false;
}
std::string value;
size_t cc;
for ( cc = 2; cc < args.size()-1; cc ++ )
{
int item = atoi(args[cc].c_str());
if (value.size())
{
value += ";";
}
int nitem = varArgsExpanded.size();
if ( item < 0 )
{
item = nitem + item;
}
if ( item < 0 || nitem <= item )
{
cmOStringStream str;
str << "index: " << item << " out of range (-" << varArgsExpanded.size() << ", " << varArgsExpanded.size()-1 << ")";
this->SetError(str.str().c_str());
return false;
}
value += varArgsExpanded[item];
}
m_Makefile->AddDefinition(variableName.c_str(), value.c_str());
return true;
}
//----------------------------------------------------------------------------
bool cmListCommand::HandleSetCommand(std::vector<std::string> const& args)
{
if(args.size() < 3)
{
this->SetError("sub-command SET requires at least two arguments.");
return false;
}
const std::string& listName = args[1];
// expand the variable
std::string listString;
if ( !this->GetListString(listString, listName.c_str()) )
{
return false;
}
size_t cc;
for ( cc = 2; cc < args.size(); ++ cc )
{
if ( listString.size() )
{
listString += ";";
}
listString += args[cc];
}
m_Makefile->AddDefinition(listName.c_str(), listString.c_str());
return true;
}
//----------------------------------------------------------------------------
bool cmListCommand::HandleInsertCommand(std::vector<std::string> const& args)
{
if(args.size() < 4)
{
this->SetError("sub-command INSERT requires at least three arguments.");
return false;
}
const std::string& listName = args[1];
// expand the variable
std::vector<std::string> varArgsExpanded;
if ( !this->GetList(varArgsExpanded, listName.c_str()) )
{
return false;
}
int item = atoi(args[2].c_str());
int nitem = varArgsExpanded.size();
if ( item < 0 )
{
item = nitem + item;
}
if ( item < 0 || nitem <= item )
{
cmOStringStream str;
str << "index: " << item << " out of range (-" << varArgsExpanded.size() << ", " << varArgsExpanded.size()-1 << ")";
this->SetError(str.str().c_str());
return false;
}
size_t cc;
size_t cnt = 0;
for ( cc = 3; cc < args.size(); ++ cc )
{
varArgsExpanded.insert(varArgsExpanded.begin()+item+cnt, args[cc]);
cnt ++;
}
std::string value;
for ( cc = 0; cc < varArgsExpanded.size(); cc ++ )
{
if (value.size())
{
value += ";";
}
value += varArgsExpanded[cc];
}
m_Makefile->AddDefinition(listName.c_str(), value.c_str());
return true;
}
//----------------------------------------------------------------------------
bool cmListCommand::HandleRemoveCommand(std::vector<std::string> const& args)
{
if(args.size() < 3)
{
this->SetError("sub-command REMOVE requires at least two arguments.");
return false;
}
const std::string& listName = args[1];
// expand the variable
std::vector<std::string> varArgsExpanded;
if ( !this->GetList(varArgsExpanded, listName.c_str()) )
{
return false;
}
size_t cc;
for ( cc = 2; cc < args.size(); ++ cc )
{
size_t kk = 0;
while ( kk < varArgsExpanded.size() )
{
if ( varArgsExpanded[kk] == args[cc] )
{
varArgsExpanded.erase(varArgsExpanded.begin()+kk);
}
kk ++;
}
}
std::string value;
for ( cc = 0; cc < varArgsExpanded.size(); cc ++ )
{
if (value.size())
{
value += ";";
}
value += varArgsExpanded[cc];
}
m_Makefile->AddDefinition(listName.c_str(), value.c_str());
return true;
}
//----------------------------------------------------------------------------
bool cmListCommand::HandleRemoveItemCommand(std::vector<std::string> const& args)
{
if(args.size() < 3)
{
this->SetError("sub-command REMOVE_ITEM requires at least two arguments.");
return false;
}
const std::string& listName = args[1];
// expand the variable
std::vector<std::string> varArgsExpanded;
if ( !this->GetList(varArgsExpanded, listName.c_str()) )
{
return false;
}
size_t cc;
std::vector<size_t> removed;
for ( cc = 2; cc < args.size(); ++ cc )
{
int item = atoi(args[cc].c_str());
int nitem = varArgsExpanded.size();
if ( item < 0 )
{
item = nitem + item;
}
if ( item < 0 || nitem <= item )
{
cmOStringStream str;
str << "index: " << item << " out of range (-" << varArgsExpanded.size() << ", " << varArgsExpanded.size()-1 << ")";
this->SetError(str.str().c_str());
return false;
}
removed.push_back(static_cast<size_t>(item));
}
std::string value;
for ( cc = 0; cc < varArgsExpanded.size(); ++ cc )
{
size_t kk;
bool found = false;
for ( kk = 0; kk < removed.size(); ++ kk )
{
if ( cc == removed[kk] )
{
found = true;
}
}
if ( !found )
{
if (value.size())
{
value += ";";
}
value += varArgsExpanded[cc];
}
}
m_Makefile->AddDefinition(listName.c_str(), value.c_str());
return true;
}

99
Source/cmListCommand.h Normal file
View File

@ -0,0 +1,99 @@
/*=========================================================================
Program: CMake - Cross-Platform Makefile Generator
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef cmListCommand_h
#define cmListCommand_h
#include "cmCommand.h"
/** \class cmListCommand
* \brief Common list operations
*
*/
class cmListCommand : public cmCommand
{
public:
/**
* This is a virtual constructor for the command.
*/
virtual cmCommand* Clone()
{
return new cmListCommand;
}
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
virtual bool InitialPass(std::vector<std::string> const& args);
/**
* This determines if the command is invoked when in script mode.
*/
virtual bool IsScriptable() { return true; }
/**
* The name of the command as specified in CMakeList.txt.
*/
virtual const char* GetName() { return "LIST";}
/**
* Succinct documentation.
*/
virtual const char* GetTerseDocumentation()
{
return "List operations.";
}
/**
* More documentation.
*/
virtual const char* GetFullDocumentation()
{
return
" LIST(LENGTH <list> <output variable>)\n"
" LIST(GET <list> <element index> [<element index> ...] <output variable>)\n"
" LIST(SET <list> <element> [<element> ...])\n"
" LIST(INSERT <list> <element_index> <element> [<element> ...])\n"
" LIST(REMOVE <variable> <value> [<value> ...])\n"
" LIST(REMOVE_ITEM <variable> <index> [<index> ...])\n"
" LIST(SORT <variable>)\n"
" LIST(REVERSE <variable>)\n"
"LENGTH will return a given list's length.\n"
"GET will return list of elements specified by indices from the list.\n"
"SET will append elements to the list.\n"
"INSERT will insert elements to the list to the specified location.\n"
"When specifying an index, negative value corresponds to index from the end "
"of the list.\n"
;
}
cmTypeMacro(cmListCommand, cmCommand);
protected:
bool HandleLengthCommand(std::vector<std::string> const& args);
bool HandleGetCommand(std::vector<std::string> const& args);
bool HandleSetCommand(std::vector<std::string> const& args);
bool HandleInsertCommand(std::vector<std::string> const& args);
bool HandleRemoveCommand(std::vector<std::string> const& args);
bool HandleRemoveItemCommand(std::vector<std::string> const& args);
bool GetList(std::vector<std::string>& list, const char* var);
bool GetListString(std::string& listString, const char* var);
};
#endif

View File

@ -0,0 +1,10 @@
SET(CMAKE_EXECUTABLE "${EXECUTABLE_OUTPUT_PATH}/cmake")
MACRO(AddCMakeTest TestName Arguments)
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/${TestName}Test.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/${TestName}Test.cmake" @ONLY IMMEDIATE)
ADD_TEST(CMake.List ${CMAKE_EXECUTABLE} -P "${CMAKE_CURRENT_BINARY_DIR}/ListTest.cmake" ${Arguments})
ENDMACRO(AddCMakeTest)
AddCMakeTest(List "")

View File

@ -0,0 +1,50 @@
MACRO(TEST command expected)
IF("x${result}" STREQUAL "x${expected}")
MESSAGE("TEST \"${command}\" success: \"${result}\" expected: \"${expected}\"")
ELSE("x${result}" STREQUAL "x${expected}")
MESSAGE(SEND_ERROR "TEST \"${command}\" failed: \"${result}\" expected: \"${expected}\"")
ENDIF("x${result}" STREQUAL "x${expected}")
ENDMACRO(TEST command expected)
SET(mylist andy bill ken brad)
LIST(LENGTH mylist result)
TEST("LENGTH mylist result" "4")
LIST(LENGTH "mylist" result)
TEST("LENGTH \"mylist\" result" "4")
LIST(GET mylist 3 2 1 0 result)
TEST("GET mylist 3 2 1 0 result" "brad;ken;bill;andy")
LIST(GET mylist 0 item0)
LIST(GET mylist 1 item1)
LIST(GET mylist 2 item2)
LIST(GET mylist 3 item3)
SET(result "${item3}" "${item0}" "${item1}" "${item2}")
TEST("GET individual 3 2 1 0 result" "brad;andy;bill;ken")
LIST(GET mylist -1 -2 -3 -4 result)
TEST("GET mylist -1 -2 -3 -4 result" "brad;ken;bill;andy")
LIST(GET mylist -1 2 -3 0 result)
TEST("GET mylist -1 2 -3 0 ${result}" "brad;ken;bill;andy")
SET(result andy)
LIST(SET result brad)
TEST("SET result brad" "andy;brad")
SET(result andy brad)
LIST(INSERT result -1 bill ken)
TEST("INSERT result -1 bill ken" "andy;bill;ken;brad")
SET(result andy bill brad ken bob)
LIST(REMOVE result bob)
TEST("REMOVE result bob" "andy;bill;brad;ken")
SET(result andy bill bob brad ken peter)
LIST(REMOVE result peter bob)
TEST("REMOVE result peter bob" "andy;bill;brad;ken")
SET(result andy bill bob brad ken peter)
LIST(REMOVE_ITEM result 2 -1)
TEST("REMOVE_ITEM result 2 -1" "andy;bill;brad;ken")