CMake/Source/cmStringCommand.cxx

921 lines
26 KiB
C++
Raw Normal View History

Simplify CMake per-source license notices Per-source copyright/license notice headers that spell out copyright holder names and years are hard to maintain and often out-of-date or plain wrong. Precise contributor information is already maintained automatically by the version control tool. Ultimately it is the receiver of a file who is responsible for determining its licensing status, and per-source notices are merely a convenience. Therefore it is simpler and more accurate for each source to have a generic notice of the license name and references to more detailed information on copyright holders and full license terms. Our `Copyright.txt` file now contains a list of Contributors whose names appeared source-level copyright notices. It also references version control history for more precise information. Therefore we no longer need to spell out the list of Contributors in each source file notice. Replace CMake per-source copyright/license notice headers with a short description of the license and links to `Copyright.txt` and online information available from "https://cmake.org/licensing". The online URL also handles cases of modules being copied out of our source into other projects, so we can drop our notices about replacing links with full license text. Run the `Utilities/Scripts/filter-notices.bash` script to perform the majority of the replacements mechanically. Manually fix up shebang lines and trailing newlines in a few files. Manually update the notices in a few files that the script does not handle.
2016-09-27 22:01:08 +03:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
2002-11-07 01:35:27 +03:00
#include "cmStringCommand.h"
#include "cmCryptoHash.h"
#include <cmsys/RegularExpression.hxx>
#include <cmsys/SystemTools.hxx>
#include <ctype.h>
#include <stdlib.h> // required for atoi
2007-04-24 00:48:56 +04:00
#include <time.h>
#include <cmTimestamp.h>
#include <cmUuid.h>
bool cmStringCommand::InitialPass(std::vector<std::string> const& args,
cmExecutionStatus&)
2002-11-07 01:35:27 +03:00
{
if (args.empty()) {
2002-11-07 01:35:27 +03:00
this->SetError("must be called with at least one argument.");
return false;
}
const std::string& subCommand = args[0];
if (subCommand == "REGEX") {
2002-11-07 01:35:27 +03:00
return this->HandleRegexCommand(args);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "REPLACE") {
return this->HandleReplaceCommand(args);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "MD5" || subCommand == "SHA1" || subCommand == "SHA224" ||
subCommand == "SHA256" || subCommand == "SHA384" ||
subCommand == "SHA512") {
return this->HandleHashCommand(args);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "TOLOWER") {
return this->HandleToUpperLowerCommand(args, false);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "TOUPPER") {
return this->HandleToUpperLowerCommand(args, true);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "COMPARE") {
return this->HandleCompareCommand(args);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "ASCII") {
2003-01-02 01:34:47 +03:00
return this->HandleAsciiCommand(args);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "CONFIGURE") {
return this->HandleConfigureCommand(args);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "LENGTH") {
2005-10-17 17:56:42 +04:00
return this->HandleLengthCommand(args);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "APPEND") {
2015-07-06 23:28:04 +03:00
return this->HandleAppendCommand(args);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "CONCAT") {
return this->HandleConcatCommand(args);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "SUBSTRING") {
2005-10-17 17:56:42 +04:00
return this->HandleSubstringCommand(args);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "STRIP") {
2007-04-27 05:50:52 +04:00
return this->HandleStripCommand(args);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "RANDOM") {
return this->HandleRandomCommand(args);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "FIND") {
return this->HandleFindCommand(args);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "TIMESTAMP") {
return this->HandleTimestampCommand(args);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "MAKE_C_IDENTIFIER") {
return this->HandleMakeCIdentifierCommand(args);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "GENEX_STRIP") {
return this->HandleGenexStripCommand(args);
2016-09-16 23:45:24 +03:00
}
if (subCommand == "UUID") {
return this->HandleUuidCommand(args);
}
std::string e = "does not recognize sub-command " + subCommand;
this->SetError(e);
2002-11-07 01:35:27 +03:00
return false;
}
bool cmStringCommand::HandleHashCommand(std::vector<std::string> const& args)
{
#if defined(CMAKE_BUILD_WITH_CMAKE)
if (args.size() != 3) {
std::ostringstream e;
e << args[0] << " requires an output variable and an input string";
this->SetError(e.str());
return false;
}
CM_AUTO_PTR<cmCryptoHash> hash(cmCryptoHash::New(args[0].c_str()));
if (hash.get()) {
std::string out = hash->HashString(args[2]);
this->Makefile->AddDefinition(args[1], out.c_str());
return true;
}
return false;
#else
std::ostringstream e;
e << args[0] << " not available during bootstrap";
this->SetError(e.str().c_str());
return false;
#endif
}
bool cmStringCommand::HandleToUpperLowerCommand(
std::vector<std::string> const& args, bool toUpper)
{
if (args.size() < 3) {
this->SetError("no output variable specified");
return false;
}
std::string outvar = args[2];
std::string output;
if (toUpper) {
output = cmSystemTools::UpperCase(args[1]);
} else {
output = cmSystemTools::LowerCase(args[1]);
}
// Store the output in the provided variable.
this->Makefile->AddDefinition(outvar, output.c_str());
return true;
}
2003-01-02 01:34:47 +03:00
bool cmStringCommand::HandleAsciiCommand(std::vector<std::string> const& args)
{
if (args.size() < 3) {
2003-01-02 01:34:47 +03:00
this->SetError("No output variable specified");
return false;
}
2003-01-02 01:34:47 +03:00
std::string::size_type cc;
std::string outvar = args[args.size() - 1];
2003-01-02 01:34:47 +03:00
std::string output = "";
for (cc = 1; cc < args.size() - 1; cc++) {
2003-01-02 01:34:47 +03:00
int ch = atoi(args[cc].c_str());
if (ch > 0 && ch < 256) {
2003-01-02 01:34:47 +03:00
output += static_cast<char>(ch);
} else {
2003-01-02 01:34:47 +03:00
std::string error = "Character with code ";
error += args[cc];
2003-01-02 01:34:47 +03:00
error += " does not exist.";
this->SetError(error);
2003-01-02 01:34:47 +03:00
return false;
}
}
2003-01-02 01:34:47 +03:00
// Store the output in the provided variable.
this->Makefile->AddDefinition(outvar, output.c_str());
2003-01-02 01:34:47 +03:00
return true;
}
bool cmStringCommand::HandleConfigureCommand(
std::vector<std::string> const& args)
{
if (args.size() < 2) {
this->SetError("No input string specified.");
return false;
2016-09-16 23:45:24 +03:00
}
if (args.size() < 3) {
this->SetError("No output variable specified.");
return false;
}
// Parse options.
bool escapeQuotes = false;
bool atOnly = false;
for (unsigned int i = 3; i < args.size(); ++i) {
if (args[i] == "@ONLY") {
atOnly = true;
} else if (args[i] == "ESCAPE_QUOTES") {
escapeQuotes = true;
} else {
std::ostringstream err;
err << "Unrecognized argument \"" << args[i] << "\"";
this->SetError(err.str());
return false;
}
}
// Configure the string.
std::string output;
2006-03-15 19:02:08 +03:00
this->Makefile->ConfigureString(args[1], output, atOnly, escapeQuotes);
// Store the output in the provided variable.
this->Makefile->AddDefinition(args[2], output.c_str());
return true;
}
2002-11-07 01:35:27 +03:00
bool cmStringCommand::HandleRegexCommand(std::vector<std::string> const& args)
{
if (args.size() < 2) {
2002-11-07 01:35:27 +03:00
this->SetError("sub-command REGEX requires a mode to be specified.");
return false;
}
2002-11-07 01:35:27 +03:00
std::string mode = args[1];
if (mode == "MATCH") {
if (args.size() < 5) {
2002-11-07 01:35:27 +03:00
this->SetError("sub-command REGEX, mode MATCH needs "
"at least 5 arguments total to command.");
return false;
}
return this->RegexMatch(args);
2016-09-16 23:45:24 +03:00
}
if (mode == "MATCHALL") {
if (args.size() < 5) {
2002-11-07 01:35:27 +03:00
this->SetError("sub-command REGEX, mode MATCHALL needs "
"at least 5 arguments total to command.");
return false;
}
return this->RegexMatchAll(args);
2016-09-16 23:45:24 +03:00
}
if (mode == "REPLACE") {
if (args.size() < 6) {
2008-08-26 20:54:06 +04:00
this->SetError("sub-command REGEX, mode REPLACE needs "
2002-11-07 01:35:27 +03:00
"at least 6 arguments total to command.");
return false;
}
return this->RegexReplace(args);
}
std::string e = "sub-command REGEX does not recognize mode " + mode;
this->SetError(e);
2002-11-07 01:35:27 +03:00
return false;
}
bool cmStringCommand::RegexMatch(std::vector<std::string> const& args)
{
2006-03-10 21:54:57 +03:00
//"STRING(REGEX MATCH <regular_expression> <output variable>
// <input> [<input>...])\n";
2002-11-07 01:35:27 +03:00
std::string regex = args[2];
std::string outvar = args[3];
this->Makefile->ClearMatches();
2002-11-07 01:35:27 +03:00
// Compile the regular expression.
cmsys::RegularExpression re;
if (!re.compile(regex.c_str())) {
std::string e =
"sub-command REGEX, mode MATCH failed to compile regex \"" + regex +
"\".";
this->SetError(e);
2002-11-07 01:35:27 +03:00
return false;
}
// Concatenate all the last arguments together.
std::string input = cmJoin(cmMakeRange(args).advance(4), std::string());
2002-11-07 01:35:27 +03:00
// Scan through the input for all matches.
std::string output;
if (re.find(input.c_str())) {
this->Makefile->StoreMatches(re);
2002-11-07 01:35:27 +03:00
std::string::size_type l = re.start();
std::string::size_type r = re.end();
if (r - l == 0) {
std::string e = "sub-command REGEX, mode MATCH regex \"" + regex +
2006-03-10 21:54:57 +03:00
"\" matched an empty string.";
this->SetError(e);
2002-11-07 01:35:27 +03:00
return false;
}
output = input.substr(l, r - l);
}
2002-11-07 01:35:27 +03:00
// Store the output in the provided variable.
this->Makefile->AddDefinition(outvar, output.c_str());
2002-11-07 01:35:27 +03:00
return true;
}
bool cmStringCommand::RegexMatchAll(std::vector<std::string> const& args)
{
//"STRING(REGEX MATCHALL <regular_expression> <output variable> <input>
2006-03-10 21:54:57 +03:00
// [<input>...])\n";
2002-11-07 01:35:27 +03:00
std::string regex = args[2];
std::string outvar = args[3];
this->Makefile->ClearMatches();
2002-11-07 01:35:27 +03:00
// Compile the regular expression.
cmsys::RegularExpression re;
if (!re.compile(regex.c_str())) {
2006-03-10 21:54:57 +03:00
std::string e =
"sub-command REGEX, mode MATCHALL failed to compile regex \"" + regex +
"\".";
this->SetError(e);
2002-11-07 01:35:27 +03:00
return false;
}
// Concatenate all the last arguments together.
std::string input = cmJoin(cmMakeRange(args).advance(4), std::string());
2002-11-07 01:35:27 +03:00
// Scan through the input for all matches.
std::string output;
const char* p = input.c_str();
while (re.find(p)) {
this->Makefile->StoreMatches(re);
2002-11-07 01:35:27 +03:00
std::string::size_type l = re.start();
std::string::size_type r = re.end();
if (r - l == 0) {
std::string e = "sub-command REGEX, mode MATCHALL regex \"" + regex +
"\" matched an empty string.";
this->SetError(e);
2002-11-07 01:35:27 +03:00
return false;
}
if (!output.empty()) {
2002-11-07 01:35:27 +03:00
output += ";";
}
output += std::string(p + l, r - l);
p += r;
}
2002-11-07 01:35:27 +03:00
// Store the output in the provided variable.
this->Makefile->AddDefinition(outvar, output.c_str());
2002-11-07 01:35:27 +03:00
return true;
}
bool cmStringCommand::RegexReplace(std::vector<std::string> const& args)
{
//"STRING(REGEX REPLACE <regular_expression> <replace_expression>
2006-03-10 21:54:57 +03:00
// <output variable> <input> [<input>...])\n"
2002-11-07 01:35:27 +03:00
std::string regex = args[2];
std::string replace = args[3];
2002-11-07 01:35:27 +03:00
std::string outvar = args[4];
2002-11-07 01:35:27 +03:00
// Pull apart the replace expression to find the escaped [0-9] values.
std::vector<RegexReplacement> replacement;
std::string::size_type l = 0;
while (l < replace.length()) {
2002-11-07 01:35:27 +03:00
std::string::size_type r = replace.find("\\", l);
if (r == std::string::npos) {
2002-11-07 01:35:27 +03:00
r = replace.length();
replacement.push_back(replace.substr(l, r - l));
} else {
if (r - l > 0) {
replacement.push_back(replace.substr(l, r - l));
2002-11-07 01:35:27 +03:00
}
if (r == (replace.length() - 1)) {
2002-11-07 01:35:27 +03:00
this->SetError("sub-command REGEX, mode REPLACE: "
"replace-expression ends in a backslash.");
return false;
}
if ((replace[r + 1] >= '0') && (replace[r + 1] <= '9')) {
replacement.push_back(replace[r + 1] - '0');
} else if (replace[r + 1] == 'n') {
2002-11-07 01:35:27 +03:00
replacement.push_back("\n");
} else if (replace[r + 1] == '\\') {
2002-11-07 01:35:27 +03:00
replacement.push_back("\\");
} else {
2002-11-07 01:35:27 +03:00
std::string e = "sub-command REGEX, mode REPLACE: Unknown escape \"";
e += replace.substr(r, 2);
e += "\" in replace-expression.";
this->SetError(e);
2002-11-07 01:35:27 +03:00
return false;
}
r += 2;
2002-11-07 01:35:27 +03:00
}
l = r;
}
this->Makefile->ClearMatches();
2002-11-07 01:35:27 +03:00
// Compile the regular expression.
cmsys::RegularExpression re;
if (!re.compile(regex.c_str())) {
std::string e =
"sub-command REGEX, mode REPLACE failed to compile regex \"" + regex +
"\".";
this->SetError(e);
2002-11-07 01:35:27 +03:00
return false;
}
// Concatenate all the last arguments together.
std::string input = cmJoin(cmMakeRange(args).advance(5), std::string());
2002-11-07 01:35:27 +03:00
// Scan through the input for all matches.
std::string output;
std::string::size_type base = 0;
while (re.find(input.c_str() + base)) {
this->Makefile->StoreMatches(re);
2002-12-03 00:35:04 +03:00
std::string::size_type l2 = re.start();
2002-11-07 01:35:27 +03:00
std::string::size_type r = re.end();
2002-11-07 01:35:27 +03:00
// Concatenate the part of the input that was not matched.
2002-12-03 00:35:04 +03:00
output += input.substr(base, l2);
2002-11-07 01:35:27 +03:00
// Make sure the match had some text.
if (r - l2 == 0) {
std::string e = "sub-command REGEX, mode REPLACE regex \"" + regex +
"\" matched an empty string.";
this->SetError(e);
2002-11-07 01:35:27 +03:00
return false;
}
2002-11-07 01:35:27 +03:00
// Concatenate the replacement for the match.
for (unsigned int i = 0; i < replacement.size(); ++i) {
if (replacement[i].number < 0) {
2002-11-07 01:35:27 +03:00
// This is just a plain-text part of the replacement.
output += replacement[i].value;
} else {
2002-11-07 01:35:27 +03:00
// Replace with part of the match.
int n = replacement[i].number;
std::string::size_type start = re.start(n);
std::string::size_type end = re.end(n);
std::string::size_type len = input.length() - base;
if ((start != std::string::npos) && (end != std::string::npos) &&
(start <= len) && (end <= len)) {
output += input.substr(base + start, end - start);
} else {
2002-11-07 01:35:27 +03:00
std::string e =
"sub-command REGEX, mode REPLACE: replace expression \"" +
replace + "\" contains an out-of-range escape for regex \"" +
regex + "\".";
this->SetError(e);
2002-11-07 01:35:27 +03:00
return false;
}
}
}
2002-11-07 01:35:27 +03:00
// Move past the match.
base += r;
}
2002-11-07 01:35:27 +03:00
// Concatenate the text after the last match.
output += input.substr(base, input.length() - base);
2002-11-07 01:35:27 +03:00
// Store the output in the provided variable.
this->Makefile->AddDefinition(outvar, output.c_str());
2002-11-07 01:35:27 +03:00
return true;
}
bool cmStringCommand::HandleFindCommand(std::vector<std::string> const& args)
{
// check if all required parameters were passed
if (args.size() < 4 || args.size() > 5) {
this->SetError("sub-command FIND requires 3 or 4 parameters.");
return false;
}
// check if the reverse flag was set or not
bool reverseMode = false;
if (args.size() == 5 && args[4] == "REVERSE") {
reverseMode = true;
}
// if we have 5 arguments the last one must be REVERSE
if (args.size() == 5 && args[4] != "REVERSE") {
this->SetError("sub-command FIND: unknown last parameter");
return false;
}
// local parameter names.
const std::string& sstring = args[1];
const std::string& schar = args[2];
const std::string& outvar = args[3];
// ensure that the user cannot accidentally specify REVERSE as a variable
if (outvar == "REVERSE") {
this->SetError("sub-command FIND does not allow one to select REVERSE as "
"the output variable. "
"Maybe you missed the actual output variable?");
return false;
}
// try to find the character and return its position
size_t pos;
if (!reverseMode) {
pos = sstring.find(schar);
} else {
pos = sstring.rfind(schar);
}
if (std::string::npos != pos) {
std::ostringstream s;
s << pos;
this->Makefile->AddDefinition(outvar, s.str().c_str());
return true;
}
// the character was not found, but this is not really an error
this->Makefile->AddDefinition(outvar, "-1");
return true;
}
bool cmStringCommand::HandleCompareCommand(
std::vector<std::string> const& args)
{
if (args.size() < 2) {
this->SetError("sub-command COMPARE requires a mode to be specified.");
return false;
}
std::string mode = args[1];
if ((mode == "EQUAL") || (mode == "NOTEQUAL") || (mode == "LESS") ||
(mode == "LESS_EQUAL") || (mode == "GREATER") ||
(mode == "GREATER_EQUAL")) {
if (args.size() < 5) {
std::string e = "sub-command COMPARE, mode ";
e += mode;
e += " needs at least 5 arguments total to command.";
this->SetError(e);
return false;
}
const std::string& left = args[2];
const std::string& right = args[3];
const std::string& outvar = args[4];
bool result;
if (mode == "LESS") {
result = (left < right);
} else if (mode == "LESS_EQUAL") {
result = (left <= right);
} else if (mode == "GREATER") {
result = (left > right);
} else if (mode == "GREATER_EQUAL") {
result = (left >= right);
} else if (mode == "EQUAL") {
result = (left == right);
} else // if(mode == "NOTEQUAL")
{
result = !(left == right);
}
if (result) {
this->Makefile->AddDefinition(outvar, "1");
} else {
this->Makefile->AddDefinition(outvar, "0");
}
return true;
}
std::string e = "sub-command COMPARE does not recognize mode " + mode;
this->SetError(e);
return false;
}
bool cmStringCommand::HandleReplaceCommand(
std::vector<std::string> const& args)
{
if (args.size() < 5) {
this->SetError("sub-command REPLACE requires at least four arguments.");
return false;
}
const std::string& matchExpression = args[1];
const std::string& replaceExpression = args[2];
const std::string& variableName = args[3];
std::string input = cmJoin(cmMakeRange(args).advance(4), std::string());
cmsys::SystemTools::ReplaceString(input, matchExpression.c_str(),
2006-03-10 21:54:57 +03:00
replaceExpression.c_str());
this->Makefile->AddDefinition(variableName, input.c_str());
return true;
}
2005-10-17 17:56:42 +04:00
bool cmStringCommand::HandleSubstringCommand(
std::vector<std::string> const& args)
2005-10-17 17:56:42 +04:00
{
if (args.size() != 5) {
this->SetError("sub-command SUBSTRING requires four arguments.");
2005-10-17 17:56:42 +04:00
return false;
}
2005-10-17 17:56:42 +04:00
const std::string& stringValue = args[1];
int begin = atoi(args[2].c_str());
int end = atoi(args[3].c_str());
const std::string& variableName = args[4];
size_t stringLength = stringValue.size();
int intStringLength = static_cast<int>(stringLength);
if (begin < 0 || begin > intStringLength) {
std::ostringstream ostr;
2006-03-10 21:54:57 +03:00
ostr << "begin index: " << begin << " is out of range 0 - "
<< stringLength;
this->SetError(ostr.str());
2005-10-17 17:56:42 +04:00
return false;
}
if (end < -1) {
std::ostringstream ostr;
ostr << "end index: " << end << " should be -1 or greater";
this->SetError(ostr.str());
2005-10-17 17:56:42 +04:00
return false;
}
2005-10-17 17:56:42 +04:00
this->Makefile->AddDefinition(variableName,
2006-03-15 19:02:08 +03:00
stringValue.substr(begin, end).c_str());
2005-10-17 17:56:42 +04:00
return true;
}
bool cmStringCommand::HandleLengthCommand(std::vector<std::string> const& args)
2005-10-17 17:56:42 +04:00
{
if (args.size() != 3) {
2005-10-17 17:56:42 +04:00
this->SetError("sub-command LENGTH requires two arguments.");
return false;
}
2005-10-17 17:56:42 +04:00
const std::string& stringValue = args[1];
const std::string& variableName = args[2];
size_t length = stringValue.size();
char buffer[1024];
2005-10-18 17:42:35 +04:00
sprintf(buffer, "%d", static_cast<int>(length));
2005-10-17 17:56:42 +04:00
this->Makefile->AddDefinition(variableName, buffer);
2005-10-17 17:56:42 +04:00
return true;
}
2015-07-06 23:28:04 +03:00
bool cmStringCommand::HandleAppendCommand(std::vector<std::string> const& args)
{
if (args.size() < 2) {
2015-07-06 23:28:04 +03:00
this->SetError("sub-command APPEND requires at least one argument.");
return false;
}
2015-07-06 23:28:04 +03:00
// Skip if nothing to append.
if (args.size() < 3) {
2015-07-06 23:28:04 +03:00
return true;
}
2015-07-06 23:28:04 +03:00
const std::string& variable = args[1];
std::string value;
const char* oldValue = this->Makefile->GetDefinition(variable);
if (oldValue) {
2015-07-06 23:28:04 +03:00
value = oldValue;
}
value += cmJoin(cmMakeRange(args).advance(2), std::string());
2015-07-06 23:28:04 +03:00
this->Makefile->AddDefinition(variable, value.c_str());
return true;
}
bool cmStringCommand::HandleConcatCommand(std::vector<std::string> const& args)
{
if (args.size() < 2) {
this->SetError("sub-command CONCAT requires at least one argument.");
return false;
}
std::string const& variableName = args[1];
std::string value = cmJoin(cmMakeRange(args).advance(2), std::string());
this->Makefile->AddDefinition(variableName, value.c_str());
return true;
}
bool cmStringCommand::HandleMakeCIdentifierCommand(
std::vector<std::string> const& args)
{
if (args.size() != 3) {
this->SetError("sub-command MAKE_C_IDENTIFIER requires two arguments.");
return false;
}
const std::string& input = args[1];
const std::string& variableName = args[2];
this->Makefile->AddDefinition(variableName,
cmSystemTools::MakeCidentifier(input).c_str());
return true;
}
bool cmStringCommand::HandleGenexStripCommand(
std::vector<std::string> const& args)
{
if (args.size() != 3) {
this->SetError("sub-command GENEX_STRIP requires two arguments.");
return false;
}
const std::string& input = args[1];
std::string result = cmGeneratorExpression::Preprocess(
input, cmGeneratorExpression::StripAllGeneratorExpressions);
const std::string& variableName = args[2];
this->Makefile->AddDefinition(variableName, result.c_str());
return true;
}
bool cmStringCommand::HandleStripCommand(std::vector<std::string> const& args)
2007-04-27 05:50:52 +04:00
{
if (args.size() != 3) {
this->SetError("sub-command STRIP requires two arguments.");
2007-04-27 05:50:52 +04:00
return false;
}
2007-04-27 05:50:52 +04:00
const std::string& stringValue = args[1];
const std::string& variableName = args[2];
size_t inStringLength = stringValue.size();
size_t startPos = inStringLength + 1;
size_t endPos = 0;
const char* ptr = stringValue.c_str();
size_t cc;
for (cc = 0; cc < inStringLength; ++cc) {
if (!isspace(*ptr)) {
if (startPos > inStringLength) {
2007-04-27 05:50:52 +04:00
startPos = cc;
}
endPos = cc;
2007-04-27 05:50:52 +04:00
}
++ptr;
}
2007-04-27 05:50:52 +04:00
size_t outLength = 0;
// if the input string didn't contain any non-space characters, return
// an empty string
if (startPos > inStringLength) {
outLength = 0;
startPos = 0;
} else {
outLength = endPos - startPos + 1;
}
this->Makefile->AddDefinition(
variableName, stringValue.substr(startPos, outLength).c_str());
2007-04-27 05:50:52 +04:00
return true;
}
bool cmStringCommand::HandleRandomCommand(std::vector<std::string> const& args)
{
if (args.size() < 2 || args.size() == 3 || args.size() == 5) {
this->SetError("sub-command RANDOM requires at least one argument.");
return false;
}
static bool seeded = false;
bool force_seed = false;
unsigned int seed = 0;
int length = 5;
const char cmStringCommandDefaultAlphabet[] = "qwertyuiopasdfghjklzxcvbnm"
"QWERTYUIOPASDFGHJKLZXCVBNM"
"0123456789";
std::string alphabet;
if (args.size() > 3) {
size_t i = 1;
size_t stopAt = args.size() - 2;
for (; i < stopAt; ++i) {
if (args[i] == "LENGTH") {
++i;
length = atoi(args[i].c_str());
} else if (args[i] == "ALPHABET") {
++i;
alphabet = args[i];
} else if (args[i] == "RANDOM_SEED") {
++i;
seed = static_cast<unsigned int>(atoi(args[i].c_str()));
force_seed = true;
}
}
}
if (alphabet.empty()) {
alphabet = cmStringCommandDefaultAlphabet;
}
double sizeofAlphabet = static_cast<double>(alphabet.size());
if (sizeofAlphabet < 1) {
this->SetError("sub-command RANDOM invoked with bad alphabet.");
return false;
}
if (length < 1) {
this->SetError("sub-command RANDOM invoked with bad length.");
return false;
}
const std::string& variableName = args[args.size() - 1];
std::vector<char> result;
if (!seeded || force_seed) {
seeded = true;
srand(force_seed ? seed : cmSystemTools::RandomSeed());
}
const char* alphaPtr = alphabet.c_str();
int cc;
for (cc = 0; cc < length; cc++) {
int idx = (int)(sizeofAlphabet * rand() / (RAND_MAX + 1.0));
result.push_back(*(alphaPtr + idx));
}
result.push_back(0);
this->Makefile->AddDefinition(variableName, &*result.begin());
return true;
}
bool cmStringCommand::HandleTimestampCommand(
std::vector<std::string> const& args)
{
if (args.size() < 2) {
this->SetError("sub-command TIMESTAMP requires at least one argument.");
return false;
2016-09-16 23:45:24 +03:00
}
if (args.size() > 4) {
this->SetError("sub-command TIMESTAMP takes at most three arguments.");
return false;
}
unsigned int argsIndex = 1;
const std::string& outputVariable = args[argsIndex++];
std::string formatString;
if (args.size() > argsIndex && args[argsIndex] != "UTC") {
formatString = args[argsIndex++];
}
bool utcFlag = false;
if (args.size() > argsIndex) {
if (args[argsIndex] == "UTC") {
utcFlag = true;
} else {
std::string e = " TIMESTAMP sub-command does not recognize option " +
args[argsIndex] + ".";
this->SetError(e);
return false;
}
}
cmTimestamp timestamp;
std::string result = timestamp.CurrentTime(formatString, utcFlag);
this->Makefile->AddDefinition(outputVariable, result.c_str());
return true;
}
bool cmStringCommand::HandleUuidCommand(std::vector<std::string> const& args)
{
#if defined(CMAKE_BUILD_WITH_CMAKE)
unsigned int argsIndex = 1;
if (args.size() < 2) {
this->SetError("UUID sub-command requires an output variable.");
return false;
}
const std::string& outputVariable = args[argsIndex++];
std::string uuidNamespaceString;
std::string uuidName;
std::string uuidType;
bool uuidUpperCase = false;
while (args.size() > argsIndex) {
if (args[argsIndex] == "NAMESPACE") {
++argsIndex;
if (argsIndex >= args.size()) {
this->SetError("UUID sub-command, NAMESPACE requires a value.");
return false;
}
uuidNamespaceString = args[argsIndex++];
} else if (args[argsIndex] == "NAME") {
++argsIndex;
if (argsIndex >= args.size()) {
this->SetError("UUID sub-command, NAME requires a value.");
return false;
}
uuidName = args[argsIndex++];
} else if (args[argsIndex] == "TYPE") {
++argsIndex;
if (argsIndex >= args.size()) {
this->SetError("UUID sub-command, TYPE requires a value.");
return false;
}
uuidType = args[argsIndex++];
} else if (args[argsIndex] == "UPPER") {
++argsIndex;
uuidUpperCase = true;
} else {
std::string e =
"UUID sub-command does not recognize option " + args[argsIndex] + ".";
this->SetError(e);
return false;
}
}
std::string uuid;
cmUuid uuidGenerator;
std::vector<unsigned char> uuidNamespace;
if (!uuidGenerator.StringToBinary(uuidNamespaceString, uuidNamespace)) {
this->SetError("UUID sub-command, malformed NAMESPACE UUID.");
return false;
}
if (uuidType == "MD5") {
uuid = uuidGenerator.FromMd5(uuidNamespace, uuidName);
} else if (uuidType == "SHA1") {
uuid = uuidGenerator.FromSha1(uuidNamespace, uuidName);
} else {
std::string e = "UUID sub-command, unknown TYPE '" + uuidType + "'.";
this->SetError(e);
return false;
}
if (uuid.empty()) {
this->SetError("UUID sub-command, generation failed.");
return false;
}
if (uuidUpperCase) {
uuid = cmSystemTools::UpperCase(uuid);
}
this->Makefile->AddDefinition(outputVariable, uuid.c_str());
return true;
#else
std::ostringstream e;
e << args[0] << " not available during bootstrap";
this->SetError(e.str().c_str());
return false;
#endif
}