mirror of
https://github.com/dlang/phobos.git
synced 2025-05-01 15:40:36 +03:00
std.process: Optimize allocations in new functions
Optimized functions: * escapeWindowsArgument * escapePosixArgument * escapeWindowsShellCommand
This commit is contained in:
parent
c9fa9f1a44
commit
4ccfb65ccc
1 changed files with 88 additions and 32 deletions
120
std/process.d
120
std/process.d
|
@ -854,6 +854,8 @@ else
|
||||||
format (2) is hidden away from the user in this module.
|
format (2) is hidden away from the user in this module.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
private char[] charAllocator(size_t size) { return new char[size]; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Quote an argument in a manner conforming to the behavior of
|
Quote an argument in a manner conforming to the behavior of
|
||||||
$(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx,
|
$(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx,
|
||||||
|
@ -865,54 +867,65 @@ string escapeWindowsArgument(string arg)
|
||||||
// Rationale for leaving this function as public:
|
// Rationale for leaving this function as public:
|
||||||
// this algorithm of escaping paths is also used in other software,
|
// this algorithm of escaping paths is also used in other software,
|
||||||
// e.g. DMD's response files.
|
// e.g. DMD's response files.
|
||||||
//
|
|
||||||
|
auto buf = escapeWindowsArgumentImpl!charAllocator(arg);
|
||||||
|
return assumeUnique(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private char[] escapeWindowsArgumentImpl(alias allocator)(string arg)
|
||||||
|
if (is(typeof(allocator(size_t.init)[0] = char.init)))
|
||||||
|
{
|
||||||
// References:
|
// References:
|
||||||
// * http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx
|
// * http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx
|
||||||
// * http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
|
// * http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
|
||||||
|
|
||||||
// Calculate the total string size and make note which characters to escape.
|
// Calculate the total string size.
|
||||||
|
|
||||||
auto escapeIt = new bool[arg.length];
|
|
||||||
// Trailing backslashes must be escaped
|
// Trailing backslashes must be escaped
|
||||||
bool escaping = true;
|
bool escaping = true;
|
||||||
// Result size = input size + 2 for surrounding quotes + 1 for the
|
// Result size = input size + 2 for surrounding quotes + 1 for the
|
||||||
// backslash for each escaped character.
|
// backslash for each escaped character.
|
||||||
size_t size = 1 + arg.length + 1;
|
size_t size = 1 + arg.length + 1;
|
||||||
|
|
||||||
foreach_reverse (i, c; arg)
|
foreach_reverse (c; arg)
|
||||||
{
|
{
|
||||||
if (c == '"')
|
if (c == '"')
|
||||||
{
|
{
|
||||||
escapeIt[i] = escaping = true;
|
escaping = true;
|
||||||
size++;
|
size++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (c == '\\')
|
if (c == '\\')
|
||||||
{
|
{
|
||||||
if (escaping)
|
if (escaping)
|
||||||
{
|
|
||||||
escapeIt[i] = true;
|
|
||||||
size++;
|
size++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
escaping = false;
|
escaping = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct result string.
|
// Construct result string.
|
||||||
|
|
||||||
char[] buf = new char[size];
|
auto buf = allocator(size);
|
||||||
size_t j = size;
|
size_t p = size;
|
||||||
buf[--j] = '"';
|
buf[--p] = '"';
|
||||||
foreach_reverse (i, c; arg)
|
escaping = true;
|
||||||
|
foreach_reverse (c; arg)
|
||||||
{
|
{
|
||||||
buf[--j] = c;
|
if (c == '"')
|
||||||
if (escapeIt[i])
|
escaping = true;
|
||||||
buf[--j] = '\\';
|
else
|
||||||
}
|
if (c != '\\')
|
||||||
buf[--j] = '"';
|
escaping = false;
|
||||||
|
|
||||||
return assumeUnique(buf);
|
buf[--p] = c;
|
||||||
|
if (escaping)
|
||||||
|
buf[--p] = '\\';
|
||||||
|
}
|
||||||
|
buf[--p] = '"';
|
||||||
|
assert(p == 0);
|
||||||
|
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
version(Windows) version(unittest)
|
version(Windows) version(unittest)
|
||||||
|
@ -957,33 +970,76 @@ version(Windows) version(unittest)
|
||||||
|
|
||||||
private string escapePosixArgument(string arg)
|
private string escapePosixArgument(string arg)
|
||||||
{
|
{
|
||||||
// '\'' means: close quoted part of argument, append an escaped
|
auto buf = escapePosixArgumentImpl!charAllocator(arg);
|
||||||
// single quote, and reopen quotes
|
return assumeUnique(buf);
|
||||||
return `'` ~ std.array.replace(arg, `'`, `'\''`) ~ `'`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string escapeShellArgument(string arg)
|
private char[] escapePosixArgumentImpl(alias allocator)(string arg)
|
||||||
|
if (is(typeof(allocator(size_t.init)[0] = char.init)))
|
||||||
|
{
|
||||||
|
// '\'' means: close quoted part of argument, append an escaped
|
||||||
|
// single quote, and reopen quotes
|
||||||
|
|
||||||
|
// Below code is equivalent to:
|
||||||
|
// return `'` ~ std.array.replace(arg, `'`, `'\''`) ~ `'`;
|
||||||
|
|
||||||
|
size_t size = 1 + arg.length + 1;
|
||||||
|
foreach (c; arg)
|
||||||
|
if (c == '\'')
|
||||||
|
size += 3;
|
||||||
|
|
||||||
|
auto buf = allocator(size);
|
||||||
|
size_t p = 0;
|
||||||
|
buf[p++] = '\'';
|
||||||
|
foreach (c; arg)
|
||||||
|
if (c == '\'')
|
||||||
|
buf[p..p+4] = `'\''`;
|
||||||
|
else
|
||||||
|
buf[p++] = c;
|
||||||
|
buf[p++] = '\'';
|
||||||
|
assert(p == size);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
private auto escapeShellArgument(alias allocator)(string arg)
|
||||||
{
|
{
|
||||||
// The unittest for this function requires special
|
// The unittest for this function requires special
|
||||||
// preparation - see below.
|
// preparation - see below.
|
||||||
|
|
||||||
version (Windows)
|
version (Windows)
|
||||||
return escapeWindowsArgument(arg);
|
return escapeWindowsArgumentImpl!allocator(arg);
|
||||||
else
|
else
|
||||||
return escapePosixArgument(arg);
|
return escapePosixArgumentImpl!allocator(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string escapeShellArguments(string[] args)
|
private string escapeShellArguments(string[] args)
|
||||||
{
|
{
|
||||||
auto result = args.dup;
|
char[] buf;
|
||||||
foreach (ref arg; result)
|
|
||||||
arg = escapeShellArgument(arg);
|
char[] allocator(size_t size)
|
||||||
return result.join(" ");
|
{
|
||||||
|
if (buf.length == 0)
|
||||||
|
return buf = new char[size];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto p = buf.length;
|
||||||
|
buf.length = buf.length + 1 + size;
|
||||||
|
buf[p++] = ' ';
|
||||||
|
return buf[p..p+size];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (arg; args)
|
||||||
|
escapeShellArgument!allocator(arg);
|
||||||
|
return assumeUnique(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
string escapeWindowsShellCommand(string command)
|
string escapeWindowsShellCommand(string command)
|
||||||
{
|
{
|
||||||
string result;
|
auto result = appender!string();
|
||||||
|
result.reserve(command.length);
|
||||||
|
|
||||||
foreach (c; command)
|
foreach (c; command)
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
|
@ -1001,12 +1057,12 @@ string escapeWindowsShellCommand(string command)
|
||||||
case '<':
|
case '<':
|
||||||
case '>':
|
case '>':
|
||||||
case '|':
|
case '|':
|
||||||
result ~= '^';
|
result.put('^');
|
||||||
goto default;
|
goto default;
|
||||||
default:
|
default:
|
||||||
result ~= c;
|
result.put(c);
|
||||||
}
|
}
|
||||||
return result;
|
return result.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string escapeShellCommandString(string command)
|
private string escapeShellCommandString(string command)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue