324 lines
9.8 KiB
C++
324 lines
9.8 KiB
C++
/*=========================================================================
|
|
|
|
Program: Insight Segmentation & Registration Toolkit
|
|
Module: $RCSfile$
|
|
Language: C++
|
|
Date: $Date$
|
|
Version: $Revision$
|
|
|
|
Copyright (c) 2001 Insight Consortium
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
* Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
|
|
* The name of the Insight Consortium, nor the names of any consortium members,
|
|
nor of any contributors, may be used to endorse or promote products derived
|
|
from this software without specific prior written permission.
|
|
|
|
* Modified source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
|
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
=========================================================================*/
|
|
#include "cmCableDefineSetCommand.h"
|
|
#include "cmCacheManager.h"
|
|
|
|
#include "cmRegularExpression.h"
|
|
|
|
|
|
// cmCableDefineSetCommand
|
|
bool cmCableDefineSetCommand::Invoke(std::vector<std::string>& args)
|
|
{
|
|
if(args.size() < 2)
|
|
{
|
|
this->SetError("called with incorrect number of arguments");
|
|
return false;
|
|
}
|
|
|
|
// This command needs access to the Cable data.
|
|
this->SetupCableData();
|
|
|
|
std::vector<std::string>::const_iterator arg = args.begin();
|
|
|
|
// The first argument is the name of the set.
|
|
m_SetName = *arg++;
|
|
|
|
// All arguments until a "SOURCE_FILES" are the elements to be placed in
|
|
// the set.
|
|
for(; (arg != args.end()) && (*arg != "SOURCE_FILES"); ++arg)
|
|
{
|
|
// If the element cannot be added, return an error.
|
|
// This can occur when a tag is not specified and can't be generated.
|
|
if(!this->AddElement(*arg))
|
|
{ return false; }
|
|
}
|
|
|
|
// If we are not at the end, the "SOURCE_FILES" keyword has been
|
|
// encountered.
|
|
if(arg != args.end())
|
|
{
|
|
// The rest of the arguments are source files to be included in
|
|
// any package which references the set.
|
|
for(++arg; arg != args.end(); ++arg)
|
|
{
|
|
if(!this->AddSourceFile(*arg))
|
|
{ return false; }
|
|
}
|
|
}
|
|
|
|
// Write this command's configuration output.
|
|
this->WriteConfiguration();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Write the CABLE configuration code to define this Set.
|
|
*/
|
|
void cmCableDefineSetCommand::WriteConfiguration() const
|
|
{
|
|
cmRegularExpression needCdataBlock("[&<>]");
|
|
|
|
// Get the ouptut information from the cmCableData.
|
|
std::ostream& os = m_CableData->GetOutputStream();
|
|
cmCableData::Indentation indent = m_CableData->GetIndentation();
|
|
|
|
// Output the code.
|
|
os << indent << "<Set name=\"" << m_SetName.c_str() << "\">" << std::endl;
|
|
for(std::vector<std::string>::const_iterator e = m_SourceHeaders.begin();
|
|
e != m_SourceHeaders.end(); ++e)
|
|
{
|
|
os << indent << " <File name=\"" << e->c_str() << "\"/>" << std::endl;
|
|
}
|
|
for(std::vector<std::string>::const_iterator e = m_InstantiationSources.begin();
|
|
e != m_InstantiationSources.end(); ++e)
|
|
{
|
|
os << indent << " <File name=\"" << e->c_str()
|
|
<< "\" purpose=\"instantiate\"/>" << std::endl;
|
|
}
|
|
for(Elements::const_iterator e = m_Elements.begin();
|
|
e != m_Elements.end(); ++e)
|
|
{
|
|
os << indent << " <Element";
|
|
// Only output the tag if it is not the empty string.
|
|
if(e->first.length() > 0)
|
|
{
|
|
os << " tag=\"" << e->first.c_str() << "\"";
|
|
}
|
|
os << ">";
|
|
if(needCdataBlock.find(e->second.c_str()))
|
|
{
|
|
os << "<![CDATA[" << e->second.c_str() << "]]>";
|
|
}
|
|
else
|
|
{
|
|
os << e->second.c_str();
|
|
}
|
|
os << "</Element>" << std::endl;
|
|
}
|
|
os << indent << "</Set>" << std::endl;
|
|
}
|
|
|
|
|
|
/**
|
|
* Add an element to the set. The given string is the argument to the
|
|
* command describing the element. There are two formats allowed:
|
|
* "code" = The code describing the element to CABLE is simply given.
|
|
* The GenerateTag() method will guess at a good tag for the
|
|
* code.
|
|
* "tag:code" = The left side of a single colon is text describing the tag.
|
|
* GenerateTag() will not be called.
|
|
*/
|
|
bool cmCableDefineSetCommand::AddElement(const std::string& arg)
|
|
{
|
|
// A regular expression to match the tagged element specification.
|
|
cmRegularExpression tagGiven("^([A-Za-z_0-9]*)[ \t]*:[ \t]*([^:].*|::.*)$");
|
|
|
|
std::string tag;
|
|
std::string code;
|
|
|
|
if(tagGiven.find(arg.c_str()))
|
|
{
|
|
// A tag was given. Use it.
|
|
tag = tagGiven.match(1);
|
|
code = tagGiven.match(2);
|
|
}
|
|
else
|
|
{
|
|
// No tag was given. Try to generate one.
|
|
if(!this->GenerateTag(arg, tag))
|
|
{ return false; }
|
|
code = arg;
|
|
}
|
|
|
|
// Add an element with the given tag and code.
|
|
m_Elements.push_back(Element(tag, code));
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Given the string representing a set element, automatically generate
|
|
* the CABLE element tag for it.
|
|
*
|
|
* **This function determines how the output language of all
|
|
* CABLE-generated wrappers will look!**
|
|
*/
|
|
bool
|
|
cmCableDefineSetCommand::GenerateTag(const std::string& element,
|
|
std::string& tag)
|
|
{
|
|
// Hold the regular expressions for matching against the element.
|
|
cmRegularExpression regex;
|
|
|
|
// If the element's code begins in a $, it is referring to a set name.
|
|
// The set's elements have their own tags, so we don't need one.
|
|
regex.compile("^[ \t]*\\$");
|
|
if(regex.find(element))
|
|
{ tag = ""; return true; }
|
|
|
|
// Test for simple integer
|
|
regex.compile("^[ \t]*([0-9]*)[ \t]*$");
|
|
if(regex.find(element))
|
|
{
|
|
tag = "_";
|
|
tag.append(regex.match(1));
|
|
return true;
|
|
}
|
|
|
|
// Test for basic integer type
|
|
regex.compile("^[ \t]*(unsigned[ ]|signed[ ])?[ \t]*(char|short|int|long|long[ ]long)[ \t]*$");
|
|
if(regex.find(element))
|
|
{
|
|
tag = "_";
|
|
if(regex.match(1) == "unsigned ")
|
|
{ tag.append("u"); }
|
|
if(regex.match(2) == "long long")
|
|
{ tag.append("llong"); }
|
|
else
|
|
{ tag.append(regex.match(2)); }
|
|
return true;
|
|
}
|
|
|
|
// Test for basic floating-point type
|
|
regex.compile("^[ \t]*(long[ ])?[ \t]*(float|double)[ \t]*$");
|
|
if(regex.find(element))
|
|
{
|
|
tag = "_";
|
|
if(regex.match(1) == "long ")
|
|
tag.append("l");
|
|
tag.append(regex.match(2));
|
|
return true;
|
|
}
|
|
|
|
// Test for basic wide-character type
|
|
regex.compile("^[ \t]*(wchar_t)[ \t]*$");
|
|
if(regex.find(element))
|
|
{
|
|
tag = "_wchar";
|
|
return true;
|
|
}
|
|
|
|
// Test for plain type name (without template arguments).
|
|
regex.compile("^[ \t]*([A-Za-z_][A-Za-z0-9_]*)[ \t]*$");
|
|
if(regex.find(element))
|
|
{
|
|
// The tag is the same as the type.
|
|
tag = regex.match(1);
|
|
return true;
|
|
}
|
|
|
|
// Test for template class instance.
|
|
regex.compile("^[ \t]*([A-Za-z_][A-Za-z0-9_]*)<.*[ \t]*$");
|
|
if(regex.find(element))
|
|
{
|
|
// The tag is the type without arguments (the arguments may have
|
|
// their own tags).
|
|
tag = regex.match(1);
|
|
return true;
|
|
}
|
|
|
|
// We can't generate a tag.
|
|
std::string err =
|
|
("doesn't know how to generate tag for element \""+element+"\" in set \""
|
|
+m_SetName+"\"\nPlease specify one with the \"tag:element\" syntax.");
|
|
this->SetError(err.c_str());
|
|
|
|
tag = "";
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Add a source file associated with this set. Any package referencing
|
|
* this set will automatically include this source file.
|
|
*/
|
|
bool cmCableDefineSetCommand::AddSourceFile(const std::string& file)
|
|
{
|
|
// We must locate the file in the include path so that we can detect
|
|
// its extension, and whether there is more than one to find.
|
|
std::string header = file+".h";
|
|
std::string txx = file+".txx";
|
|
m_Makefile->ExpandVariablesInString(header);
|
|
m_Makefile->ExpandVariablesInString(txx);
|
|
|
|
// See if the file just exists here. The compiler's search path will
|
|
// locate it.
|
|
if(cmSystemTools::FileExists(header.c_str()))
|
|
{
|
|
m_SourceHeaders.push_back(header);
|
|
// See if there is a matching .txx as well.
|
|
if(cmSystemTools::FileExists(txx.c_str()))
|
|
{
|
|
m_InstantiationSources.push_back(txx);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// We must look for the file in the include search path.
|
|
const std::vector<std::string>& includeDirectories =
|
|
m_Makefile->GetIncludeDirectories();
|
|
|
|
for(std::vector<std::string>::const_iterator dir = includeDirectories.begin();
|
|
dir != includeDirectories.end(); ++dir)
|
|
{
|
|
std::string path = *dir + "/";
|
|
m_Makefile->ExpandVariablesInString(path);
|
|
if(cmSystemTools::FileExists((path+header).c_str()))
|
|
{
|
|
m_SourceHeaders.push_back(header);
|
|
// See if there is a matching .txx as well.
|
|
if(cmSystemTools::FileExists((path+txx).c_str()))
|
|
{
|
|
m_InstantiationSources.push_back(txx);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// We couldn't locate the source file. Report the error.
|
|
std::string err = "couldn't find source file " + header;
|
|
this->SetError(err.c_str());
|
|
return false;
|
|
}
|