
Use the clang RemoveCStrCalls tool to automatically migrate the code. This was only run on linux, so does not have any positive or negative effect on other platforms.
368 lines
8.8 KiB
C++
368 lines
8.8 KiB
C++
/*============================================================================
|
|
CMake - Cross Platform Makefile Generator
|
|
Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
|
|
|
|
Distributed under the OSI-approved BSD License (the "License");
|
|
see accompanying file Copyright.txt for details.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY; without even the
|
|
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
See the License for more information.
|
|
============================================================================*/
|
|
#include "cmCommandArgumentParserHelper.h"
|
|
|
|
#include "cmSystemTools.h"
|
|
#include "cmMakefile.h"
|
|
|
|
#include "cmCommandArgumentLexer.h"
|
|
|
|
int cmCommandArgument_yyparse( yyscan_t yyscanner );
|
|
//
|
|
cmCommandArgumentParserHelper::cmCommandArgumentParserHelper()
|
|
{
|
|
this->WarnUninitialized = false;
|
|
this->CheckSystemVars = false;
|
|
this->FileLine = -1;
|
|
this->FileName = 0;
|
|
this->RemoveEmpty = true;
|
|
this->EmptyVariable[0] = 0;
|
|
strcpy(this->DCURLYVariable, "${");
|
|
strcpy(this->RCURLYVariable, "}");
|
|
strcpy(this->ATVariable, "@");
|
|
strcpy(this->DOLLARVariable, "$");
|
|
strcpy(this->LCURLYVariable, "{");
|
|
strcpy(this->BSLASHVariable, "\\");
|
|
|
|
this->NoEscapeMode = false;
|
|
this->ReplaceAtSyntax = false;
|
|
}
|
|
|
|
|
|
cmCommandArgumentParserHelper::~cmCommandArgumentParserHelper()
|
|
{
|
|
this->CleanupParser();
|
|
}
|
|
|
|
void cmCommandArgumentParserHelper::SetLineFile(long line, const char* file)
|
|
{
|
|
this->FileLine = line;
|
|
this->FileName = file;
|
|
}
|
|
|
|
char* cmCommandArgumentParserHelper::AddString(const std::string& str)
|
|
{
|
|
if ( str.empty() )
|
|
{
|
|
return this->EmptyVariable;
|
|
}
|
|
char* stVal = new char[str.size()+1];
|
|
strcpy(stVal, str.c_str());
|
|
this->Variables.push_back(stVal);
|
|
return stVal;
|
|
}
|
|
|
|
char* cmCommandArgumentParserHelper::ExpandSpecialVariable(const char* key,
|
|
const char* var)
|
|
{
|
|
if ( !key )
|
|
{
|
|
return this->ExpandVariable(var);
|
|
}
|
|
if(!var)
|
|
{
|
|
return this->EmptyVariable;
|
|
}
|
|
if ( strcmp(key, "ENV") == 0 )
|
|
{
|
|
char *ptr = getenv(var);
|
|
if (ptr)
|
|
{
|
|
if (this->EscapeQuotes)
|
|
{
|
|
return this->AddString(cmSystemTools::EscapeQuotes(ptr));
|
|
}
|
|
else
|
|
{
|
|
return ptr;
|
|
}
|
|
}
|
|
return this->EmptyVariable;
|
|
}
|
|
if ( strcmp(key, "CACHE") == 0 )
|
|
{
|
|
if(const char* c = this->Makefile->GetCacheManager()->GetCacheValue(var))
|
|
{
|
|
if(this->EscapeQuotes)
|
|
{
|
|
return this->AddString(cmSystemTools::EscapeQuotes(c));
|
|
}
|
|
else
|
|
{
|
|
return this->AddString(c);
|
|
}
|
|
}
|
|
return this->EmptyVariable;
|
|
}
|
|
cmOStringStream e;
|
|
e << "Syntax $" << key << "{} is not supported. "
|
|
<< "Only ${}, $ENV{}, and $CACHE{} are allowed.";
|
|
this->SetError(e.str());
|
|
return 0;
|
|
}
|
|
|
|
char* cmCommandArgumentParserHelper::ExpandVariable(const char* var)
|
|
{
|
|
if(!var)
|
|
{
|
|
return 0;
|
|
}
|
|
if(this->FileLine >= 0 && strcmp(var, "CMAKE_CURRENT_LIST_LINE") == 0)
|
|
{
|
|
cmOStringStream ostr;
|
|
ostr << this->FileLine;
|
|
return this->AddString(ostr.str());
|
|
}
|
|
const char* value = this->Makefile->GetDefinition(var);
|
|
if(!value && !this->RemoveEmpty)
|
|
{
|
|
// check to see if we need to print a warning
|
|
// if strict mode is on and the variable has
|
|
// not been "cleared"/initialized with a set(foo ) call
|
|
if(this->WarnUninitialized && !this->Makefile->VariableInitialized(var))
|
|
{
|
|
if (this->CheckSystemVars ||
|
|
cmSystemTools::IsSubDirectory(this->FileName,
|
|
this->Makefile->GetHomeDirectory()) ||
|
|
cmSystemTools::IsSubDirectory(this->FileName,
|
|
this->Makefile->GetHomeOutputDirectory()))
|
|
{
|
|
cmOStringStream msg;
|
|
cmListFileBacktrace bt;
|
|
cmListFileContext lfc;
|
|
lfc.FilePath = this->FileName;
|
|
lfc.Line = this->FileLine;
|
|
bt.push_back(lfc);
|
|
msg << "uninitialized variable \'" << var << "\'";
|
|
this->Makefile->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING,
|
|
msg.str(), bt);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
if (this->EscapeQuotes && value)
|
|
{
|
|
return this->AddString(cmSystemTools::EscapeQuotes(value));
|
|
}
|
|
return this->AddString(value ? value : "");
|
|
}
|
|
|
|
char* cmCommandArgumentParserHelper::ExpandVariableForAt(const char* var)
|
|
{
|
|
if(this->ReplaceAtSyntax)
|
|
{
|
|
// try to expand the variable
|
|
char* ret = this->ExpandVariable(var);
|
|
// if the return was 0 and we want to replace empty strings
|
|
// then return an empty string
|
|
if(!ret && this->RemoveEmpty)
|
|
{
|
|
return this->AddString("");
|
|
}
|
|
// if the ret was not 0, then return it
|
|
if(ret)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
// at this point we want to put it back because of one of these cases:
|
|
// - this->ReplaceAtSyntax is false
|
|
// - this->ReplaceAtSyntax is true, but this->RemoveEmpty is false,
|
|
// and the variable was not defined
|
|
std::string ref = "@";
|
|
ref += var;
|
|
ref += "@";
|
|
return this->AddString(ref);
|
|
}
|
|
|
|
char* cmCommandArgumentParserHelper::CombineUnions(char* in1, char* in2)
|
|
{
|
|
if ( !in1 )
|
|
{
|
|
return in2;
|
|
}
|
|
else if ( !in2 )
|
|
{
|
|
return in1;
|
|
}
|
|
size_t len = strlen(in1) + strlen(in2) + 1;
|
|
char* out = new char [ len ];
|
|
strcpy(out, in1);
|
|
strcat(out, in2);
|
|
this->Variables.push_back(out);
|
|
return out;
|
|
}
|
|
|
|
void cmCommandArgumentParserHelper::AllocateParserType
|
|
(cmCommandArgumentParserHelper::ParserType* pt,const char* str, int len)
|
|
{
|
|
pt->str = 0;
|
|
if ( len == 0 )
|
|
{
|
|
len = static_cast<int>(strlen(str));
|
|
}
|
|
if ( len == 0 )
|
|
{
|
|
return;
|
|
}
|
|
pt->str = new char[ len + 1 ];
|
|
strncpy(pt->str, str, len);
|
|
pt->str[len] = 0;
|
|
this->Variables.push_back(pt->str);
|
|
}
|
|
|
|
bool cmCommandArgumentParserHelper::HandleEscapeSymbol
|
|
(cmCommandArgumentParserHelper::ParserType* pt, char symbol)
|
|
{
|
|
switch ( symbol )
|
|
{
|
|
case '\\':
|
|
case '"':
|
|
case ' ':
|
|
case '#':
|
|
case '(':
|
|
case ')':
|
|
case '$':
|
|
case '@':
|
|
case '^':
|
|
this->AllocateParserType(pt, &symbol, 1);
|
|
break;
|
|
case ';':
|
|
this->AllocateParserType(pt, "\\;", 2);
|
|
break;
|
|
case 't':
|
|
this->AllocateParserType(pt, "\t", 1);
|
|
break;
|
|
case 'n':
|
|
this->AllocateParserType(pt, "\n", 1);
|
|
break;
|
|
case 'r':
|
|
this->AllocateParserType(pt, "\r", 1);
|
|
break;
|
|
case '0':
|
|
this->AllocateParserType(pt, "\0", 1);
|
|
break;
|
|
default:
|
|
{
|
|
cmOStringStream e;
|
|
e << "Invalid escape sequence \\" << symbol;
|
|
this->SetError(e.str());
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void cmCommandArgument_SetupEscapes(yyscan_t yyscanner, bool noEscapes);
|
|
|
|
int cmCommandArgumentParserHelper::ParseString(const char* str, int verb)
|
|
{
|
|
if ( !str)
|
|
{
|
|
return 0;
|
|
}
|
|
this->Verbose = verb;
|
|
this->InputBuffer = str;
|
|
this->InputBufferPos = 0;
|
|
this->CurrentLine = 0;
|
|
|
|
this->Result = "";
|
|
|
|
yyscan_t yyscanner;
|
|
cmCommandArgument_yylex_init(&yyscanner);
|
|
cmCommandArgument_yyset_extra(this, yyscanner);
|
|
cmCommandArgument_SetupEscapes(yyscanner, this->NoEscapeMode);
|
|
int res = cmCommandArgument_yyparse(yyscanner);
|
|
cmCommandArgument_yylex_destroy(yyscanner);
|
|
if ( res != 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
this->CleanupParser();
|
|
|
|
if ( Verbose )
|
|
{
|
|
std::cerr << "Expanding [" << str << "] produced: ["
|
|
<< this->Result.c_str() << "]" << std::endl;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void cmCommandArgumentParserHelper::CleanupParser()
|
|
{
|
|
std::vector<char*>::iterator sit;
|
|
for ( sit = this->Variables.begin();
|
|
sit != this->Variables.end();
|
|
++ sit )
|
|
{
|
|
delete [] *sit;
|
|
}
|
|
this->Variables.erase(this->Variables.begin(), this->Variables.end());
|
|
}
|
|
|
|
int cmCommandArgumentParserHelper::LexInput(char* buf, int maxlen)
|
|
{
|
|
if ( maxlen < 1 )
|
|
{
|
|
return 0;
|
|
}
|
|
if ( this->InputBufferPos < this->InputBuffer.size() )
|
|
{
|
|
buf[0] = this->InputBuffer[ this->InputBufferPos++ ];
|
|
if ( buf[0] == '\n' )
|
|
{
|
|
this->CurrentLine ++;
|
|
}
|
|
return(1);
|
|
}
|
|
else
|
|
{
|
|
buf[0] = '\n';
|
|
return( 0 );
|
|
}
|
|
}
|
|
|
|
void cmCommandArgumentParserHelper::Error(const char* str)
|
|
{
|
|
unsigned long pos = static_cast<unsigned long>(this->InputBufferPos);
|
|
cmOStringStream ostr;
|
|
ostr << str << " (" << pos << ")";
|
|
this->SetError(ostr.str());
|
|
}
|
|
|
|
void cmCommandArgumentParserHelper::SetMakefile(const cmMakefile* mf)
|
|
{
|
|
this->Makefile = mf;
|
|
this->WarnUninitialized = mf->GetCMakeInstance()->GetWarnUninitialized();
|
|
this->CheckSystemVars = mf->GetCMakeInstance()->GetCheckSystemVars();
|
|
}
|
|
|
|
void cmCommandArgumentParserHelper::SetResult(const char* value)
|
|
{
|
|
if ( !value )
|
|
{
|
|
this->Result = "";
|
|
return;
|
|
}
|
|
this->Result = value;
|
|
}
|
|
|
|
void cmCommandArgumentParserHelper::SetError(std::string const& msg)
|
|
{
|
|
// Keep only the first error.
|
|
if(this->ErrorString.empty())
|
|
{
|
|
this->ErrorString = msg;
|
|
}
|
|
}
|