ENH: add atonly support to cmCommandArgumentParserHelper.cxx and remove old non-yacc parser code from cmMakefile.cxx

This commit is contained in:
Bill Hoffman 2007-02-09 13:44:37 -05:00
parent 0e1ae13f7c
commit 0e95a190bc
3 changed files with 88 additions and 210 deletions

View File

@ -27,7 +27,7 @@ cmCommandArgumentParserHelper::cmCommandArgumentParserHelper()
{
this->FileLine = -1;
this->FileName = 0;
this->RemoveEmpty = true;
this->EmptyVariable[0] = 0;
strcpy(this->DCURLYVariable, "${");
strcpy(this->RCURLYVariable, "}");
@ -38,6 +38,7 @@ cmCommandArgumentParserHelper::cmCommandArgumentParserHelper()
this->NoEscapeMode = false;
this->ReplaceAtSyntax = false;
this->AtOnly = false;
}
@ -71,6 +72,18 @@ char* cmCommandArgumentParserHelper::ExpandSpecialVariable(const char* key,
{
return this->ExpandVariable(var);
}
if(this->AtOnly)
{
std::string ref = "$";
ref += key;
ref += "{";
if(var)
{
ref += var;
}
ref += "}";
return this->AddString(ref.c_str());
}
if ( strcmp(key, "ENV") == 0 )
{
char *ptr = getenv(var);
@ -92,8 +105,21 @@ char* cmCommandArgumentParserHelper::ExpandSpecialVariable(const char* key,
return 0;
}
char* cmCommandArgumentParserHelper::ExpandVariable(const char* var)
char* cmCommandArgumentParserHelper::ExpandVariable(const char* var,
bool doingAt)
{
// if we are in AtOnly mode, and we are not expanding an @ variable
// then put back the ${var} unexpanded
if(!doingAt && this->AtOnly)
{
std::string ref = "${";
if(var)
{
ref += var;
}
ref += "}";
return this->AddString(ref.c_str());
}
if(!var)
{
return 0;
@ -109,6 +135,10 @@ char* cmCommandArgumentParserHelper::ExpandVariable(const char* var)
return this->AddString(ostr.str().c_str());
}
const char* value = this->Makefile->GetDefinition(var);
if(!value && !this->RemoveEmpty)
{
return 0;
}
if (this->EscapeQuotes && value)
{
return this->AddString(cmSystemTools::EscapeQuotes(value).c_str());
@ -120,15 +150,28 @@ char* cmCommandArgumentParserHelper::ExpandVariableForAt(const char* var)
{
if(this->ReplaceAtSyntax)
{
return this->ExpandVariable(var);
}
else
{
std::string ref = "@";
ref += var;
ref += "@";
return this->AddString(ref.c_str());
// try to expand the variable
char* ret = this->ExpandVariable(var, true);
// if the return was 0 and we want to replace empty strings
// then return an empty string
if(!ret && this->RemoveEmpty)
{
return this->AddString(ret);
}
// 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.c_str());
}
char* cmCommandArgumentParserHelper::CombineUnions(char* in1, char* in2)

View File

@ -58,7 +58,7 @@ public:
char* CombineUnions(char* in1, char* in2);
char* ExpandSpecialVariable(const char* key, const char* var);
char* ExpandVariable(const char* var);
char* ExpandVariable(const char* var, bool doingAt=false);
char* ExpandVariableForAt(const char* var);
void SetResult(const char* value);
@ -70,6 +70,8 @@ public:
void SetEscapeQuotes(bool b) { this->EscapeQuotes = b; }
void SetNoEscapeMode(bool b) { this->NoEscapeMode = b; }
void SetReplaceAtSyntax(bool b) { this->ReplaceAtSyntax = b; }
void SetRemoveEmpty(bool b) { this->RemoveEmpty = b; }
void SetAtOnly(bool b) { this->AtOnly = b; }
const char* GetError() { return this->ErrorString.c_str(); }
char EmptyVariable[1];
@ -104,6 +106,8 @@ private:
std::string ErrorString;
bool NoEscapeMode;
bool ReplaceAtSyntax;
bool RemoveEmpty;
bool AtOnly;
};
#endif

View File

@ -1684,214 +1684,45 @@ const char *cmMakefile::ExpandVariablesInString(std::string& source,
// It also supports the $ENV{VAR} syntax where VAR is looked up in
// the current environment variables.
bool notParsed = true;
if ( !atOnly )
cmCommandArgumentParserHelper parser;
parser.SetMakefile(this);
parser.SetLineFile(line, filename);
parser.SetEscapeQuotes(escapeQuotes);
parser.SetNoEscapeMode(noEscapes);
parser.SetReplaceAtSyntax(replaceAt);
parser.SetRemoveEmpty(removeEmpty);
parser.SetAtOnly(atOnly);
int res = parser.ParseString(source.c_str(), 0);
if ( res )
{
cmCommandArgumentParserHelper parser;
parser.SetMakefile(this);
parser.SetLineFile(line, filename);
parser.SetEscapeQuotes(escapeQuotes);
parser.SetNoEscapeMode(noEscapes);
parser.SetReplaceAtSyntax(replaceAt);
int res = parser.ParseString(source.c_str(), 0);
if ( res )
{
source = parser.GetResult();
notParsed = false;
}
else
{
cmOStringStream error;
error << "Syntax error in cmake code at\n"
<< (filename?filename:"(no filename given)")
<< ":" << line << ":\n"
<< parser.GetError() << ", when parsing string \""
<< source.c_str() << "\"";
const char* versionValue
= this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
int major = 0;
int minor = 0;
if ( versionValue )
{
sscanf(versionValue, "%d.%d", &major, &minor);
}
if ( major < 2 || major == 2 && minor < 1 )
{
cmSystemTools::Error(error.str().c_str());
cmSystemTools::SetFatalErrorOccured();
return source.c_str();
}
else
{
cmSystemTools::Message(error.str().c_str());
}
}
source = parser.GetResult();
}
if ( notParsed )
else
{
// start by look for $ or @ in the string
std::string::size_type markerPos;
if(atOnly)
cmOStringStream error;
error << "Syntax error in cmake code at\n"
<< (filename?filename:"(no filename given)")
<< ":" << line << ":\n"
<< parser.GetError() << ", when parsing string \""
<< source.c_str() << "\"";
const char* versionValue
= this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
int major = 0;
int minor = 0;
if ( versionValue )
{
markerPos = source.find_first_of("@");
sscanf(versionValue, "%d.%d", &major, &minor);
}
else
{
markerPos = source.find_first_of("$@");
}
// if not found, or found as the last character, then leave quickly as
// nothing needs to be expanded
if((markerPos == std::string::npos) || (markerPos >= source.size()-1))
if ( major < 2 || major == 2 && minor < 1 )
{
cmSystemTools::Error(error.str().c_str());
cmSystemTools::SetFatalErrorOccured();
return source.c_str();
}
// current position
std::string::size_type currentPos =0; // start at 0
std::string result; // string with replacements
// go until the the end of the string
while((markerPos != std::string::npos) && (markerPos < source.size()-1))
else
{
// grab string from currentPos to the start of the variable
// and add it to the result
result += source.substr(currentPos, markerPos - currentPos);
char endVariableMarker; // what is the end of the variable @ or }
int markerStartSize = 1; // size of the start marker 1 or 2 or 5
if(!atOnly && source[markerPos] == '$')
{
// ${var} case
if(source[markerPos+1] == '{')
{
endVariableMarker = '}';
markerStartSize = 2;
}
// $ENV{var} case
else if(markerPos+4 < source.size() &&
source[markerPos+4] == '{' &&
!source.substr(markerPos+1, 3).compare("ENV"))
{
endVariableMarker = '}';
markerStartSize = 5;
}
else
{
// bogus $ with no { so add $ to result and move on
result += '$'; // add bogus $ back into string
currentPos = markerPos+1; // move on
// set end var to space so we can tell bogus
endVariableMarker = ' ';
}
}
else
{
// @VAR case
endVariableMarker = '@';
}
// if it was a valid variable (started with @ or ${ or $ENV{ )
if(endVariableMarker != ' ')
{
markerPos += markerStartSize; // move past marker
// find the end variable marker starting at the markerPos
// make sure it is a valid variable between
std::string::size_type endVariablePos =
source.find_first_not_of(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
markerPos);
if(endVariablePos != std::string::npos &&
source[endVariablePos] != endVariableMarker)
{
endVariablePos = std::string::npos;
}
if(endVariablePos == std::string::npos)
{
// no end marker found so add the bogus start
if(endVariableMarker == '@')
{
result += '@';
}
else
{
result += (markerStartSize == 5 ? "$ENV{" : "${");
}
currentPos = markerPos;
}
else
{
// good variable remove it
std::string var =
source.substr(markerPos, endVariablePos - markerPos);
bool found = false;
if (markerStartSize == 5) // $ENV{
{
char *ptr = getenv(var.c_str());
if (ptr)
{
if (escapeQuotes)
{
result += cmSystemTools::EscapeQuotes(ptr);
}
else
{
result += ptr;
}
found = true;
}
}
else
{
const char* lookup = this->GetDefinition(var.c_str());
if(lookup)
{
if (escapeQuotes)
{
result += cmSystemTools::EscapeQuotes(lookup);
}
else
{
result += lookup;
}
found = true;
}
else if(filename && (var == "CMAKE_CURRENT_LIST_FILE"))
{
result += filename;
found = true;
}
else if(line >= 0 && (var == "CMAKE_CURRENT_LIST_LINE"))
{
cmOStringStream ostr;
ostr << line;
result += ostr.str();
found = true;
}
}
// if found add to result, if not, then it gets blanked
if (!found)
{
// if no definition is found then add the var back
if(!removeEmpty && endVariableMarker == '@')
{
result += "@";
result += var;
result += "@";
}
}
// lookup var, and replace it
currentPos = endVariablePos+1;
}
}
if(atOnly)
{
markerPos = source.find_first_of("@", currentPos);
}
else
{
markerPos = source.find_first_of("$@", currentPos);
}
cmSystemTools::Message(error.str().c_str());
}
result += source.substr(currentPos); // pick up the rest of the string
source = result;
}
return source.c_str();
}