few optimizations building string vector with arguments

- avoid unneeded copying (don't gather remaining string)
- don't build args byte by byte

Signed-off-by: Sergey G. Brester <serg.brester@sebres.de>
Reviewed-by: Tino Reichardt <milky-zfs@mcmilk.de>
This commit is contained in:
sebres
2023-03-22 14:50:45 +01:00
committed by Tino Reichardt
parent cc1192c7d9
commit 45c245645d
3 changed files with 51 additions and 24 deletions

View File

@@ -6,21 +6,23 @@
namespace NCommandLineParser { namespace NCommandLineParser {
bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2) static const wchar_t * _SplitCommandLine(const wchar_t* s, UString &dest)
{ {
unsigned qcount = 0, bcount = 0; unsigned qcount = 0, bcount = 0;
wchar_t c; const wchar_t *s = src.Ptr(); wchar_t c; const wchar_t *f, *b;
dest1.Empty(); dest.Empty();
// skip spaces:
while (isblank(*s)) { s++; };
b = f = s;
while ((c = *s++) != 0) while ((c = *s++) != 0)
{ {
switch (c) switch (c)
{ {
case L'\\': case L'\\':
// a backslash - firstly add it as a regular char, // a backslash - count them up to quote-char or regular char
// we'll delete escaped later (if followed by quote):
dest1 += c;
bcount++; bcount++;
break; break;
case L'"': case L'"':
@@ -28,8 +30,8 @@ bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2)
if (!(bcount & 1)) if (!(bcount & 1))
{ {
// preceded by an even number of '\', this is half that // preceded by an even number of '\', this is half that
// number of '\' (delete bcount/2 chars): // number of '\':
dest1.DeleteFrom(dest1.Len() - bcount/2); dest.AddFrom(f, (unsigned)(s - f - bcount/2 - 1)); f = s;
// count quote chars: // count quote chars:
qcount++; qcount++;
} }
@@ -37,8 +39,8 @@ bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2)
{ {
// preceded by an odd number of '\', this is half that // preceded by an odd number of '\', this is half that
// number of '\' followed by an escaped '"': // number of '\' followed by an escaped '"':
dest1.DeleteFrom(dest1.Len() - bcount/2 - 1); dest.AddFrom(f, (unsigned)(s - f - bcount/2 - 2)); f = s;
dest1 += L'"'; dest += L'"';
} }
bcount = 0; bcount = 0;
// now count the number of consecutive quotes (inclusive // now count the number of consecutive quotes (inclusive
@@ -48,10 +50,11 @@ bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2)
s++; s++;
if (++qcount == 3) if (++qcount == 3)
{ {
dest1 += L'"'; dest += L'"';
qcount = 0; qcount = 1;
} }
} }
f = s;
if (qcount == 2) if (qcount == 2)
qcount = 0; qcount = 0;
break; break;
@@ -61,37 +64,50 @@ bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2)
if (!qcount) if (!qcount)
{ {
// end of argument: // end of argument:
bcount = 0; dest.AddFrom(f, (unsigned)(s - f - 1)); f = s;
// skip to the next one: // skip to the next one:
while (isblank(*s)) { s++; }; while (isblank(*s)) { s++; };
bcount = 0;
goto done; goto done;
} }
// no break - a space as regular char: // no break - a space as regular char:
default: default:
// a regular character // a regular character, reset backslash counter
dest1 += c;
bcount = 0; bcount = 0;
} }
} }
s--; // back to NTS-zero char s--; // back to NTS-zero char
dest.AddFrom(f, (unsigned)(s - f));
done: done:
dest2 = s; // remaining part if argument was found, otherwise NULL:
return (dest1.Len() || src[0]); return (dest.Len() || *b) ? s : NULL;
} }
void SplitCommandLine(const UString &s, UStringVector &parts) bool SplitCommandLine(const UString& src, UString& dest1, UString& dest2)
{ {
UString sTemp (s); const wchar_t *s = src.Ptr();
sTemp.Trim(); s = _SplitCommandLine(s, dest1);
if (s) {
dest2 = s;
return true;
} else {
dest2.Empty();
return false;
}
}
void SplitCommandLine(const UString &src, UStringVector &parts)
{
const wchar_t *s = src.Ptr();
parts.Clear(); parts.Clear();
for (;;) for (;;)
{ {
UString s1, s2; UString s1;
if (SplitCommandLine(sTemp, s1, s2)) s = _SplitCommandLine(s, s1);
if (s)
parts.Add(s1); parts.Add(s1);
if (s2.IsEmpty()) if (!s || !*s)
break; break;
sTemp = s2;
} }
} }

View File

@@ -1206,6 +1206,16 @@ UString &UString::operator=(const UString &s)
return *this; return *this;
} }
void UString::AddFrom(const wchar_t *s, unsigned len) // no check
{
if (len) {
Grow(len);
wmemcpy(_chars + _len, s, len);
_len += len;
_chars[_len] = 0;
}
}
void UString::SetFrom(const wchar_t *s, unsigned len) // no check void UString::SetFrom(const wchar_t *s, unsigned len) // no check
{ {
if (len > _limit) if (len > _limit)

View File

@@ -628,6 +628,7 @@ public:
UString &operator=(char c) { return (*this)=((wchar_t)(unsigned char)c); } UString &operator=(char c) { return (*this)=((wchar_t)(unsigned char)c); }
UString &operator=(const wchar_t *s); UString &operator=(const wchar_t *s);
UString &operator=(const UString &s); UString &operator=(const UString &s);
void AddFrom(const wchar_t *s, unsigned len); // no check
void SetFrom(const wchar_t *s, unsigned len); // no check void SetFrom(const wchar_t *s, unsigned len); // no check
void SetFromBstr(LPCOLESTR s); void SetFromBstr(LPCOLESTR s);
UString &operator=(const char *s); UString &operator=(const char *s);