cmOutputConverter: implement Shell__GetArgument using ostringstream

This removes the need to calculate the resulting string length
beforehand.
This commit is contained in:
Daniel Pfeifer 2016-06-15 23:41:46 +02:00
parent 909d51bece
commit d645b03e9c
2 changed files with 39 additions and 192 deletions

View File

@ -15,6 +15,7 @@
#include "cmake.h"
#include <assert.h>
#include <sstream>
#include <ctype.h> /* isalpha */
#include <string.h> /* strlen */
@ -328,19 +329,9 @@ std::string cmOutputConverter::EscapeForShell(const std::string& str,
flags |= Shell_Flag_NMake;
}
// Compute the buffer size needed.
int size = (this->GetState()->UseWindowsShell()
? Shell_GetArgumentSizeForWindows(str.c_str(), flags)
: Shell_GetArgumentSizeForUnix(str.c_str(), flags));
// Compute the shell argument itself.
std::vector<char> arg(size);
if (this->GetState()->UseWindowsShell()) {
Shell_GetArgumentForWindows(str.c_str(), &arg[0], flags);
} else {
Shell_GetArgumentForUnix(str.c_str(), &arg[0], flags);
}
return std::string(&arg[0]);
return this->GetState()->UseWindowsShell()
? Shell_GetArgumentForWindows(str.c_str(), flags)
: Shell_GetArgumentForUnix(str.c_str(), flags);
}
std::string cmOutputConverter::EscapeForCMake(const std::string& str)
@ -369,18 +360,7 @@ std::string cmOutputConverter::EscapeForCMake(const std::string& str)
std::string cmOutputConverter::EscapeWindowsShellArgument(const char* arg,
int shell_flags)
{
char local_buffer[1024];
char* buffer = local_buffer;
int size = Shell_GetArgumentSizeForWindows(arg, shell_flags);
if (size > 1024) {
buffer = new char[size];
}
Shell_GetArgumentForWindows(arg, buffer, shell_flags);
std::string result(buffer);
if (buffer != local_buffer) {
delete[] buffer;
}
return result;
return Shell_GetArgumentForWindows(arg, shell_flags);
}
cmOutputConverter::FortranFormat cmOutputConverter::GetFortranFormat(
@ -586,12 +566,10 @@ int cmOutputConverter::Shell__ArgumentNeedsQuotes(const char* in, int isUnix,
return 0;
}
int cmOutputConverter::Shell__GetArgumentSize(const char* in, int isUnix,
int flags)
std::string cmOutputConverter::Shell__GetArgument(const char* in, int isUnix,
int flags)
{
/* Start with the length of the original argument, plus one for
either a terminating null or a separating space. */
int size = (int)strlen(in) + 1;
std::ostringstream out;
/* String iterator. */
const char* c;
@ -599,116 +577,17 @@ int cmOutputConverter::Shell__GetArgumentSize(const char* in, int isUnix,
/* Keep track of how many backslashes have been encountered in a row. */
int windows_backslashes = 0;
/* Scan the string for characters that require escaping or quoting. */
for (c = in; *c; ++c) {
/* Look for $(MAKEVAR) syntax if requested. */
if (flags & Shell_Flag_AllowMakeVariables) {
/* Skip over the make variable references if any are present. */
c = Shell__SkipMakeVariables(c);
/* Stop if we have reached the end of the string. */
if (!*c) {
break;
}
}
/* Check whether this character needs escaping for the shell. */
if (isUnix) {
/* On Unix a few special characters need escaping even inside a
quoted argument. */
if (*c == '\\' || *c == '"' || *c == '`' || *c == '$') {
/* This character needs a backslash to escape it. */
++size;
}
} else if (flags & Shell_Flag_EchoWindows) {
/* On Windows the built-in command shell echo never needs escaping. */
} else {
/* On Windows only backslashes and double-quotes need escaping. */
if (*c == '\\') {
/* Found a backslash. It may need to be escaped later. */
++windows_backslashes;
} else if (*c == '"') {
/* Found a double-quote. We need to escape it and all
immediately preceding backslashes. */
size += windows_backslashes + 1;
windows_backslashes = 0;
} else {
/* Found another character. This eliminates the possibility
that any immediately preceding backslashes will be
escaped. */
windows_backslashes = 0;
}
}
/* Check whether this character needs escaping for a make tool. */
if (*c == '$') {
if (flags & Shell_Flag_Make) {
/* In Makefiles a dollar is written $$ so we need one extra
character. */
++size;
} else if (flags & Shell_Flag_VSIDE) {
/* In a VS IDE a dollar is written "$" so we need two extra
characters. */
size += 2;
}
} else if (*c == '#') {
if ((flags & Shell_Flag_Make) && (flags & Shell_Flag_WatcomWMake)) {
/* In Watcom WMake makefiles a pound is written $# so we need
one extra character. */
++size;
}
} else if (*c == '%') {
if ((flags & Shell_Flag_VSIDE) ||
((flags & Shell_Flag_Make) &&
((flags & Shell_Flag_MinGWMake) || (flags & Shell_Flag_NMake)))) {
/* In the VS IDE, NMake, or MinGW make a percent is written %%
so we need one extra characters. */
size += 1;
}
} else if (*c == ';') {
if (flags & Shell_Flag_VSIDE) {
/* In a VS IDE a semicolon is written ";" so we need two extra
characters. */
size += 2;
}
}
}
/* Check whether the argument needs surrounding quotes. */
if (Shell__ArgumentNeedsQuotes(in, isUnix, flags)) {
/* Surrounding quotes are needed. Allocate space for them. */
if ((flags & Shell_Flag_WatcomQuote) && (isUnix)) {
size += 2;
}
size += 2;
/* We must escape all ending backslashes when quoting on windows. */
size += windows_backslashes;
}
return size;
}
char* cmOutputConverter::Shell__GetArgument(const char* in, char* out,
int isUnix, int flags)
{
/* String iterator. */
const char* c;
/* Keep track of how many backslashes have been encountered in a row. */
int windows_backslashes = 0;
/* Whether the argument must be quoted. */
int needQuotes = Shell__ArgumentNeedsQuotes(in, isUnix, flags);
if (needQuotes) {
/* Add the opening quote for this argument. */
if (flags & Shell_Flag_WatcomQuote) {
if (isUnix) {
*out++ = '"';
out << '"';
}
*out++ = '\'';
out << '\'';
} else {
*out++ = '"';
out << '"';
}
}
@ -720,7 +599,7 @@ char* cmOutputConverter::Shell__GetArgument(const char* in, char* out,
if (skip != c) {
/* Copy to the end of the make variable references. */
while (c != skip) {
*out++ = *c++;
out << *c++;
}
/* The make variable reference eliminates any escaping needed
@ -740,7 +619,7 @@ char* cmOutputConverter::Shell__GetArgument(const char* in, char* out,
quoted argument. */
if (*c == '\\' || *c == '"' || *c == '`' || *c == '$') {
/* This character needs a backslash to escape it. */
*out++ = '\\';
out << '\\';
}
} else if (flags & Shell_Flag_EchoWindows) {
/* On Windows the built-in command shell echo never needs escaping. */
@ -754,11 +633,11 @@ char* cmOutputConverter::Shell__GetArgument(const char* in, char* out,
backslashes. */
while (windows_backslashes > 0) {
--windows_backslashes;
*out++ = '\\';
out << '\\';
}
/* Add the backslash to escape the double-quote. */
*out++ = '\\';
out << '\\';
} else {
/* We encountered a normal character. This eliminates any
escaping needed for preceding backslashes. */
@ -771,8 +650,7 @@ char* cmOutputConverter::Shell__GetArgument(const char* in, char* out,
if (flags & Shell_Flag_Make) {
/* In Makefiles a dollar is written $$. The make tool will
replace it with just $ before passing it to the shell. */
*out++ = '$';
*out++ = '$';
out << "$$";
} else if (flags & Shell_Flag_VSIDE) {
/* In a VS IDE a dollar is written "$". If this is written in
an un-quoted argument it starts a quoted segment, inserts
@ -780,34 +658,30 @@ char* cmOutputConverter::Shell__GetArgument(const char* in, char* out,
argument it ends quoting, inserts the $ and restarts
quoting. Either way the $ is isolated from surrounding
text to avoid looking like a variable reference. */
*out++ = '"';
*out++ = '$';
*out++ = '"';
out << "\"$\"";
} else {
/* Otherwise a dollar is written just $. */
*out++ = '$';
out << '$';
}
} else if (*c == '#') {
if ((flags & Shell_Flag_Make) && (flags & Shell_Flag_WatcomWMake)) {
/* In Watcom WMake makefiles a pound is written $#. The make
tool will replace it with just # before passing it to the
shell. */
*out++ = '$';
*out++ = '#';
out << "$#";
} else {
/* Otherwise a pound is written just #. */
*out++ = '#';
out << '#';
}
} else if (*c == '%') {
if ((flags & Shell_Flag_VSIDE) ||
((flags & Shell_Flag_Make) &&
((flags & Shell_Flag_MinGWMake) || (flags & Shell_Flag_NMake)))) {
/* In the VS IDE, NMake, or MinGW make a percent is written %%. */
*out++ = '%';
*out++ = '%';
out << "%%";
} else {
/* Otherwise a percent is written just %. */
*out++ = '%';
out << '%';
}
} else if (*c == ';') {
if (flags & Shell_Flag_VSIDE) {
@ -816,16 +690,14 @@ char* cmOutputConverter::Shell__GetArgument(const char* in, char* out,
inserts the ; and ends the segment. If it is written in a
quoted argument it ends quoting, inserts the ; and restarts
quoting. Either way the ; is isolated. */
*out++ = '"';
*out++ = ';';
*out++ = '"';
out << "\";\"";
} else {
/* Otherwise a semicolon is written just ;. */
*out++ = ';';
out << ';';
}
} else {
/* Store this character. */
*out++ = *c;
out << *c;
}
}
@ -833,45 +705,31 @@ char* cmOutputConverter::Shell__GetArgument(const char* in, char* out,
/* Add enough backslashes to escape any trailing ones. */
while (windows_backslashes > 0) {
--windows_backslashes;
*out++ = '\\';
out << '\\';
}
/* Add the closing quote for this argument. */
if (flags & Shell_Flag_WatcomQuote) {
*out++ = '\'';
out << '\'';
if (isUnix) {
*out++ = '"';
out << '"';
}
} else {
*out++ = '"';
out << '"';
}
}
/* Store a terminating null without incrementing. */
*out = 0;
return out;
return out.str();
}
char* cmOutputConverter::Shell_GetArgumentForWindows(const char* in, char* out,
int flags)
std::string cmOutputConverter::Shell_GetArgumentForWindows(const char* in,
int flags)
{
return Shell__GetArgument(in, out, 0, flags);
return Shell__GetArgument(in, 0, flags);
}
char* cmOutputConverter::Shell_GetArgumentForUnix(const char* in, char* out,
int flags)
std::string cmOutputConverter::Shell_GetArgumentForUnix(const char* in,
int flags)
{
return Shell__GetArgument(in, out, 1, flags);
}
int cmOutputConverter::Shell_GetArgumentSizeForWindows(const char* in,
int flags)
{
return Shell__GetArgumentSize(in, 0, flags);
}
int cmOutputConverter::Shell_GetArgumentSizeForUnix(const char* in, int flags)
{
return Shell__GetArgumentSize(in, 1, flags);
return Shell__GetArgument(in, 1, flags);
}

View File

@ -126,17 +126,8 @@ public:
* modify the generated quoting and escape sequences to work under
* alternative environments.
*/
static char* Shell_GetArgumentForWindows(const char* in, char* out,
int flags);
static char* Shell_GetArgumentForUnix(const char* in, char* out, int flags);
/**
* Compute the size of the buffer required to store the output from
* Shell_GetArgumentForWindows or Shell_GetArgumentForUnix. The flags
* passed must be identical between the two calls.
*/
static int Shell_GetArgumentSizeForWindows(const char* in, int flags);
static int Shell_GetArgumentSizeForUnix(const char* in, int flags);
static std::string Shell_GetArgumentForWindows(const char* in, int flags);
static std::string Shell_GetArgumentForUnix(const char* in, int flags);
std::string EscapeForShell(const std::string& str, bool makeVars = false,
bool forEcho = false,
@ -182,9 +173,7 @@ private:
static int Shell__CharIsMakeVariableName(char c);
static const char* Shell__SkipMakeVariables(const char* c);
static int Shell__ArgumentNeedsQuotes(const char* in, int isUnix, int flags);
static int Shell__GetArgumentSize(const char* in, int isUnix, int flags);
static char* Shell__GetArgument(const char* in, char* out, int isUnix,
int flags);
static std::string Shell__GetArgument(const char* in, int isUnix, int flags);
private:
cmState::Snapshot StateSnapshot;