diff --git a/Source/Engine/Core/Types/StringView.cpp b/Source/Engine/Core/Types/StringView.cpp
index a9b40e6a3..8667d0c58 100644
--- a/Source/Engine/Core/Types/StringView.cpp
+++ b/Source/Engine/Core/Types/StringView.cpp
@@ -50,6 +50,33 @@ StringView StringView::Substring(int32 startIndex, int32 count) const
return StringView(Get() + startIndex, count);
}
+StringView StringView::Trim() const
+{
+ if (IsEmpty())
+ return *this;
+
+ int32 start = 0;
+ int32 end = Length() - 1;
+
+ while (start <= end)
+ {
+ if (!StringUtils::IsWhitespace((*this)[start]))
+ break;
+ start++;
+ }
+ while (end >= 0)
+ {
+ if (!StringUtils::IsWhitespace((*this)[end]))
+ break;
+ end--;
+ }
+
+ const int32 count = end - start + 1;
+ if (start >= 0 && start + count <= Length() && count >= 0)
+ return StringView(_data + start, count);
+ return Empty;
+}
+
String StringView::ToString() const
{
return String(_data, _length);
diff --git a/Source/Engine/Core/Types/StringView.h b/Source/Engine/Core/Types/StringView.h
index 40a763bee..89b4dde2a 100644
--- a/Source/Engine/Core/Types/StringView.h
+++ b/Source/Engine/Core/Types/StringView.h
@@ -382,6 +382,11 @@ public:
/// The substring created from String data.
StringView Substring(int32 startIndex, int32 count) const;
+ ///
+ /// Removes trailing whitespace characters from end and begin of the string.
+ ///
+ StringView Trim() const;
+
public:
String ToString() const;
StringAnsi ToStringAnsi() const;
diff --git a/Source/Engine/Engine/CommandLine.cpp b/Source/Engine/Engine/CommandLine.cpp
index d8bde1864..d2b5fa374 100644
--- a/Source/Engine/Engine/CommandLine.cpp
+++ b/Source/Engine/Engine/CommandLine.cpp
@@ -1,245 +1,243 @@
// Copyright (c) Wojciech Figat. All rights reserved.
#include "CommandLine.h"
-#include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Utilities.h"
-#include "Engine/Core/Types/StringView.h"
-#include
+#include "Engine/Core/Collections/Array.h"
+static Array Args;
CommandLine::OptionsData CommandLine::Options;
-bool ParseArg(Char* ptr, Char*& start, Char*& end)
+bool InitCommandLine(const Char* cmdLine)
{
- // Skip leading whitespaces
- while (*ptr && StringUtils::IsWhitespace(*ptr))
- ptr++;
-
- bool isInComma = false;
- bool isUglyQuote = false;
- start = ptr;
- while (*ptr)
- {
- Char c = *ptr;
- if (StringUtils::IsWhitespace(c) && !isInComma)
- {
- // End
- end = ptr;
- return false;
- }
- else if (c == '\"' || c == '\'')
- {
- if (isInComma)
- {
- // End comma
- end = ptr;
- if (isUglyQuote)
- {
- ptr += 2;
- end -= 2;
- }
- return false;
- }
- else
- {
- // Special case (eg. Visual Studio Code adds soo many quotes to the args with spaces)
- isUglyQuote = StringUtils::Compare(ptr, TEXT("\"\\\\\""), 4) == 0;
- if (isUglyQuote)
- {
- ptr += 3;
- }
-
- // Start comma
- isInComma = true;
- start = ptr + 1;
- }
- }
-
- ptr++;
- }
- return true;
-}
-
-bool CommandLine::Parse(const Char* cmdLine)
-{
- Options.CmdLine = cmdLine;
+ auto& options = CommandLine::Options;
#if FLAX_TESTS
// Configure engine for test running environment
- Options.Headless = true;
- Options.Null = true;
- Options.Mute = true;
- Options.Std = true;
+ options.Headless = true;
+ options.Null = true;
+ options.Mute = true;
+ options.Std = true;
#endif
+ // Parse command line
int32 length = StringUtils::Length(cmdLine);
if (length == 0)
return false;
- Array buffer;
- buffer.Resize(length + 2);
- Platform::MemoryCopy(buffer.Get(), cmdLine, sizeof(Char) * length);
- buffer[length++] = ' ';
- buffer[length++] = 0;
- Char* end = buffer.Get() + length;
-
- Char* pos;
- Char* argStart;
- Char* argEnd;
- int32 len;
- (void)argStart;
- (void)argEnd;
+ if (CommandLine::Parse(StringView(cmdLine, length), Args))
+ return true;
+ // Parse common switches
+ bool valueBool;
+ StringView valueString;
+#define PARSE_BOOL_SWITCH(arg, field) if (CommandLine::Get(TEXT(arg), valueBool)) options.field = valueBool
+#define PARSE_ARG_SWITCH(arg, field) if (CommandLine::Get(TEXT(arg), valueString)) options.field = valueString
+ PARSE_BOOL_SWITCH("windowed", Windowed);
+ PARSE_BOOL_SWITCH("fullscreen", Fullscreen);
+ PARSE_BOOL_SWITCH("vsync", VSync);
+ PARSE_BOOL_SWITCH("novsync", NoVSync);
+ PARSE_BOOL_SWITCH("nolog", NoLog);
+ PARSE_BOOL_SWITCH("std", Std);
#if PLATFORM_HAS_HEADLESS_MODE
-#define PARSE_ERROR(msg) std::cout << msg << std::endl
-#else
-#define PARSE_ERROR(msg) // Ignore
+ PARSE_BOOL_SWITCH("headless", Headless);
#endif
-
-#define PARSE_BOOL_SWITCH(text, field) \
- pos = (Char*)StringUtils::FindIgnoreCase(buffer.Get(), TEXT(text)); \
- if (pos) \
- { \
- len = ARRAY_COUNT(text) - 1; \
- Utilities::UnsafeMemoryCopy(pos, pos + len, (end - pos - len) * 2); \
- *(end - len) = 0; \
- end -= len; \
- Options.field = true; \
- }
-#define PARSE_ARG_SWITCH(text, field) \
- pos = (Char*)StringUtils::FindIgnoreCase(buffer.Get(), TEXT(text)); \
- if (pos) \
- { \
- len = ARRAY_COUNT(text) - 1; \
- if (ParseArg(pos + len, argStart, argEnd)) \
- { \
- PARSE_ERROR("Failed to parse argument."); \
- return true; \
- } \
- Options.field = String(argStart, static_cast(argEnd - argStart)); \
- len = static_cast((argEnd - pos) + 1); \
- Utilities::UnsafeMemoryCopy(pos, pos + len, (end - pos - len) * 2); \
- *(end - len) = 0; \
- end -= len; \
- }
-
-#define PARSE_ARG_OPT_SWITCH(text, field) \
- pos = (Char*)StringUtils::FindIgnoreCase(buffer.Get(), TEXT(text)); \
- if (pos) \
- { \
- len = ARRAY_COUNT(text) - 1; \
- if (ParseArg(pos + len, argStart, argEnd)) \
- Options.field = String::Empty; \
- else \
- { \
- Options.field = String(argStart, static_cast(argEnd - argStart)); \
- len = static_cast((argEnd - pos) + 1); \
- Utilities::UnsafeMemoryCopy(pos, pos + len, (end - pos - len) * 2); \
- *(end - len) = 0; \
- end -= len; \
- } \
- }
-
- PARSE_BOOL_SWITCH("-windowed ", Windowed);
- PARSE_BOOL_SWITCH("-fullscreen ", Fullscreen);
- PARSE_BOOL_SWITCH("-vsync ", VSync);
- PARSE_BOOL_SWITCH("-novsync ", NoVSync);
- PARSE_BOOL_SWITCH("-nolog ", NoLog);
- PARSE_BOOL_SWITCH("-std ", Std);
-#if PLATFORM_HAS_HEADLESS_MODE
- PARSE_BOOL_SWITCH("-headless ", Headless);
-#endif
- PARSE_BOOL_SWITCH("-d3d12 ", D3D12);
- PARSE_BOOL_SWITCH("-d3d11 ", D3D11);
- PARSE_BOOL_SWITCH("-d3d10 ", D3D10);
- PARSE_BOOL_SWITCH("-null ", Null);
- PARSE_BOOL_SWITCH("-vulkan ", Vulkan);
- PARSE_BOOL_SWITCH("-nvidia ", NVIDIA);
- PARSE_BOOL_SWITCH("-amd ", AMD);
- PARSE_BOOL_SWITCH("-intel ", Intel);
- PARSE_BOOL_SWITCH("-mute ", Mute);
- PARSE_BOOL_SWITCH("-lowdpi ", LowDPI);
-
+ PARSE_BOOL_SWITCH("d3d12", D3D12);
+ PARSE_BOOL_SWITCH("d3d11", D3D11);
+ PARSE_BOOL_SWITCH("d3d10", D3D10);
+ PARSE_BOOL_SWITCH("null", Null);
+ PARSE_BOOL_SWITCH("vulkan", Vulkan);
+ PARSE_BOOL_SWITCH("nvidia", NVIDIA);
+ PARSE_BOOL_SWITCH("amd", AMD);
+ PARSE_BOOL_SWITCH("intel", Intel);
+ PARSE_BOOL_SWITCH("mute", Mute);
+ PARSE_BOOL_SWITCH("lowdpi", LowDPI);
#if PLATFORM_LINUX && PLATFORM_SDL
- PARSE_BOOL_SWITCH("-wayland ", Wayland);
- PARSE_BOOL_SWITCH("-x11 ", X11);
+ PARSE_BOOL_SWITCH("wayland", Wayland);
+ PARSE_BOOL_SWITCH("x11", X11);
#endif
-
#if USE_EDITOR
- PARSE_BOOL_SWITCH("-clearcache ", ClearCache);
- PARSE_BOOL_SWITCH("-clearcooker ", ClearCookerCache);
- PARSE_ARG_SWITCH("-project ", Project);
- PARSE_BOOL_SWITCH("-lastproject ", LastProject);
- PARSE_BOOL_SWITCH("-new ", NewProject);
- PARSE_BOOL_SWITCH("-genprojectfiles ", GenProjectFiles);
- PARSE_ARG_SWITCH("-build ", Build);
- PARSE_BOOL_SWITCH("-skipcompile ", SkipCompile);
- PARSE_BOOL_SWITCH("-shaderdebug ", ShaderDebug);
- PARSE_BOOL_SWITCH("-exit ", Exit);
- PARSE_ARG_OPT_SWITCH("-play ", Play);
+ PARSE_BOOL_SWITCH("clearcache", ClearCache);
+ PARSE_BOOL_SWITCH("clearcooker", ClearCookerCache);
+ PARSE_ARG_SWITCH("project", Project);
+ PARSE_BOOL_SWITCH("lastproject", LastProject);
+ PARSE_BOOL_SWITCH("new", NewProject);
+ PARSE_BOOL_SWITCH("genprojectfiles", GenProjectFiles);
+ PARSE_ARG_SWITCH("build", Build);
+ PARSE_BOOL_SWITCH("skipcompile", SkipCompile);
+ PARSE_BOOL_SWITCH("shaderdebug", ShaderDebug);
+ PARSE_BOOL_SWITCH("exit", Exit);
+ PARSE_ARG_SWITCH("play", Play);
#endif
#if USE_EDITOR || !BUILD_RELEASE
- PARSE_BOOL_SWITCH("-shaderprofile ", ShaderProfile);
- PARSE_BOOL_SWITCH("-gpudebug ", GPUDebug);
+ PARSE_BOOL_SWITCH("shaderprofile", ShaderProfile);
+ PARSE_BOOL_SWITCH("gpudebug", GPUDebug);
#endif
+#undef PARSE_BOOL_SWITCH
+#undef PARSE_ARG_SWITCH
return false;
}
-bool CommandLine::ParseArguments(const StringView& cmdLine, Array& arguments)
+bool CommandLine::Get(const StringView& arg)
{
- int32 start = 0;
- int32 quotesStart = -1;
- int32 length = cmdLine.Length();
- for (int32 i = 0; i < length; i++)
- {
- if (cmdLine[i] == ' ' && quotesStart == -1)
- {
- int32 count = i - start;
- if (count > 0)
- arguments.Add(StringAnsi(cmdLine.Substring(start, count)));
- start = i + 1;
- }
- else if (cmdLine[i] == '\"')
- {
- if (quotesStart >= 0)
- {
- if (i + 1 < length && cmdLine[i + 1] != ' ')
- {
- // End quotes are in the middle of the current word,
- // continue until the end of the current word.
- }
- else
- {
- int32 offset = 1;
- if (quotesStart == start && cmdLine[start] == '\"')
- {
- // Word starts and ends with quotes, only include the quoted content.
- quotesStart++;
- offset--;
- }
- else if (quotesStart != start)
- {
- // Start quotes in the middle of the word, include the whole word.
- quotesStart = start;
- }
+ StringView value;
+ return Get(arg, value);
+}
- int32 count = i - quotesStart + offset;
- if (count > 0)
- arguments.Add(StringAnsi(cmdLine.Substring(quotesStart, count)));
- start = i + 1;
- }
- quotesStart = -1;
- }
- else
- {
- quotesStart = i;
- }
+bool CommandLine::Get(const StringView& arg, StringView& value)
+{
+ for (const Arg& a : Args)
+ {
+ if (a.Name.Length() == arg.Length() && StringUtils::CompareIgnoreCase(*a.Name, *arg, arg.Length()) == 0)
+ {
+ value = a.Value;
+ return true;
}
}
- const int32 count = length - start;
- if (count > 0)
- arguments.Add(StringAnsi(cmdLine.Substring(start, count)));
- if (quotesStart >= 0)
- return true; // Missing last closing quote
+ return false;
+}
+
+bool CommandLine::Get(const StringView& arg, bool& value)
+{
+ StringView str;
+ if (Get(arg, str))
+ {
+ value = true; // Assume true when arg is set
+ if (str.HasChars())
+ StringUtils::Parse(str.Get(), str.Length(), &value);
+ return true;
+ }
+ return false;
+}
+
+bool CommandLine::Get(const StringView& arg, int32& value)
+{
+ StringView str;
+ if (Get(arg, str))
+ {
+ value = 0;
+ if (str.HasChars())
+ StringUtils::Parse(str.Get(), str.Length(), &value);
+ return true;
+ }
+ return false;
+}
+
+bool CommandLine::Parse(const StringView& commandLine, Array& args)
+{
+ int32 length = commandLine.Length();
+ bool addedEmptyArg = false;
+ for (int32 i = 0; i < length;)
+ {
+ // Skip white space
+ while (i < length && StringUtils::IsWhitespace(commandLine[i]))
+ i++;
+
+ // Read option prefix
+ if (i == length)
+ break;
+ bool wholeQuote = commandLine[i] == '\"';
+ if (wholeQuote)
+ i++;
+ if (i == length)
+ break;
+ if (commandLine[i] == '-')
+ i++;
+ else if (commandLine[i] == '/')
+ i++;
+
+ // Skip white space
+ while (i < length && StringUtils::IsWhitespace(commandLine[i]))
+ i++;
+
+ // Read option name
+ int32 nameStart = i;
+ while (i < length && commandLine[i] != '-' && commandLine[i] != '=' && !StringUtils::IsWhitespace(commandLine[i]))
+ i++;
+ if (wholeQuote)
+ i--;
+ int32 nameEnd = i;
+ StringView name = commandLine.Substring(nameStart, nameEnd - nameStart);
+
+ // If previous argument was empty and this one is a quote then assume it's a value for the previous argument (without '=')
+ if (wholeQuote && addedEmptyArg)
+ {
+ args.Last().Value = name;
+ i++;
+ continue;
+ }
+
+ // Skip white space
+ while (i < length && StringUtils::IsWhitespace(commandLine[i]))
+ i++;
+
+ // Check if has no value
+ if (i >= length - 1 || commandLine[i] != '=')
+ {
+ args.Add({ name, StringView::Empty });
+ addedEmptyArg = true;
+ if (wholeQuote)
+ i++;
+ if (i < length && commandLine[i] != '\"')
+ i++;
+ continue;
+ }
+ addedEmptyArg = false;
+
+ // Read value
+ i++;
+ int32 valueStart, valueEnd;
+ if (length > i + 1 && commandLine[i] == '\\' && commandLine[i + 1] == '\"')
+ {
+ valueStart = i + 2;
+ i++;
+ while (i + 1 < length && commandLine[i] != '\\' && commandLine[i + 1] != '\"')
+ i++;
+ valueEnd = i;
+ i += 2;
+ if (wholeQuote)
+ {
+ while (i < length && commandLine[i] != '\"')
+ i++;
+ i++;
+ }
+ }
+ else if (commandLine[i] == '\"' || commandLine[i] == '\'')
+ {
+ Char quoteChar = commandLine[i];
+ valueStart = i + 1;
+ i++;
+ while (i < length && commandLine[i] != quoteChar)
+ i++;
+ valueEnd = i;
+ i++;
+ if (wholeQuote)
+ {
+ while (i < length && commandLine[i] != '\"')
+ i++;
+ i++;
+ }
+ }
+ else if (wholeQuote)
+ {
+ valueStart = i;
+ while (i < length && commandLine[i] != '\"')
+ i++;
+ valueEnd = i;
+ i++;
+ }
+ else
+ {
+ valueStart = i;
+ while (i < length && commandLine[i] != ' ')
+ i++;
+ valueEnd = i;
+ }
+ StringView value = commandLine.Substring(valueStart, valueEnd - valueStart);
+ value = value.Trim();
+ if (value.StartsWith(TEXT("\\\"")) && value.EndsWith(TEXT("\\\"")))
+ value = value.Substring(2, value.Length() - 4);
+ args.Add({ name, value });
+ }
return false;
}
diff --git a/Source/Engine/Engine/CommandLine.h b/Source/Engine/Engine/CommandLine.h
index 55ecfc4e5..79c9c30ae 100644
--- a/Source/Engine/Engine/CommandLine.h
+++ b/Source/Engine/Engine/CommandLine.h
@@ -3,16 +3,15 @@
#pragma once
#include "Engine/Core/Types/String.h"
+#include "Engine/Core/Types/StringView.h"
#include "Engine/Core/Types/Nullable.h"
-#include "Engine/Core/Collections/Array.h"
///
/// Command line options helper.
///
-class CommandLine
+class FLAXENGINE_API CommandLine
{
public:
-
struct OptionsData
{
///
@@ -199,19 +198,46 @@ public:
static OptionsData Options;
public:
+ ///
+ /// The command line option data.
+ ///
+ struct FLAXENGINE_API Arg
+ {
+ // The name.
+ StringView Name;
+ // The value.
+ StringView Value;
+ };
///
- /// Parses the input command line.
+ /// Gets the specific command line option value. Returns true if given argument has been set.
///
- /// The command line.
- /// True if failed, otherwise false.
- static bool Parse(const Char* cmdLine);
+ /// True if given argument has been provided in program command line.
+ static bool Get(const StringView& arg);
///
- /// Parses the command line arguments string into string list of arguments.
+ /// Gets the specific command line option value. Returns true if given argument has been set and provides it's value (as string).
///
- /// The command line.
- /// The parsed arguments
+ /// True if given argument has been provided in program command line.
+ static bool Get(const StringView& arg, StringView& value);
+
+ ///
+ /// Gets the specific command line option value. Returns true if given argument has been set and provides it's value (as boolean). Returns ture if argument doesn't have specific value.
+ ///
+ /// True if given argument has been provided in program command line.
+ static bool Get(const StringView& arg, bool& value);
+
+ ///
+ /// Gets the specific command line option value. Returns true if given argument has been set and provides it's value (as integer).
+ ///
+ /// True if given argument has been provided in program command line.
+ static bool Get(const StringView& arg, int32& value);
+
+ ///
+ /// Parses the specified command line.
+ ///
+ /// The input command line.
+ /// The parsed arguments
/// True if failed, otherwise false.
- static bool ParseArguments(const StringView& cmdLine, Array& arguments);
+ static bool Parse(const StringView& cmdLine, Array& args);
};
diff --git a/Source/Engine/Engine/Engine.cpp b/Source/Engine/Engine/Engine.cpp
index afaa8824c..5259cc564 100644
--- a/Source/Engine/Engine/Engine.cpp
+++ b/Source/Engine/Engine/Engine.cpp
@@ -87,7 +87,8 @@ int32 Engine::OnInit(const Char* cmdLine)
EngineService::Sort();
- if (CommandLine::Parse(cmdLine))
+ extern bool InitCommandLine(const Char* cmdLine);
+ if (InitCommandLine(cmdLine))
{
Platform::Fatal(TEXT("Invalid command line."));
return -1;
diff --git a/Source/Engine/Platform/Base/StringUtilsBase.cpp b/Source/Engine/Platform/Base/StringUtilsBase.cpp
index 96f0fd2dc..350d43272 100644
--- a/Source/Engine/Platform/Base/StringUtilsBase.cpp
+++ b/Source/Engine/Platform/Base/StringUtilsBase.cpp
@@ -499,6 +499,28 @@ bool StringUtils::Parse(const char* str, float* result)
#endif
}
+bool StringUtils::Parse(const Char* str, int32 length, bool* result)
+{
+ if ((length == 1 && CompareIgnoreCase(str, TEXT("1"), length) == 0) ||
+ (length == 4 && CompareIgnoreCase(str, TEXT("true"), length) == 0))
+ {
+ *result = true;
+ return false;
+ }
+ if ((length == 1 && CompareIgnoreCase(str, TEXT("0"), length) == 0) ||
+ (length == 5 && CompareIgnoreCase(str, TEXT("false"), length) == 0))
+ {
+ *result = false;
+ return false;
+ }
+ return true;
+}
+
+String StringUtils::ToString(bool value)
+{
+ return value ? TEXT("true") : TEXT("false");
+}
+
String StringUtils::ToString(int32 value)
{
return String::Format(TEXT("{}"), value);
diff --git a/Source/Engine/Platform/StringUtils.h b/Source/Engine/Platform/StringUtils.h
index faa8127f8..be877fc6a 100644
--- a/Source/Engine/Platform/StringUtils.h
+++ b/Source/Engine/Platform/StringUtils.h
@@ -336,7 +336,11 @@ public:
// Parses text to the scalar value. Returns true if failed to convert the value.
static bool Parse(const char* str, float* result);
+ // Parses text to the boolean value. Returns true if failed to convert the value.
+ static bool Parse(const Char* str, int32 length, bool* result);
+
public:
+ static String ToString(bool value);
static String ToString(int32 value);
static String ToString(int64 value);
static String ToString(uint32 value);
diff --git a/Source/Engine/Tests/TestCommandLine.cpp b/Source/Engine/Tests/TestCommandLine.cpp
deleted file mode 100644
index 8aaaa2aa8..000000000
--- a/Source/Engine/Tests/TestCommandLine.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) Wojciech Figat. All rights reserved.
-
-#include "Engine/Engine/CommandLine.h"
-#include "Engine/Core/Types/StringView.h"
-#include "Engine/Core/Collections/Array.h"
-#include
-
-TEST_CASE("CommandLine")
-{
- SECTION("Test Argument Parser")
- {
- SECTION("Single quoted word")
- {
- String input("\"word\"");
- Array arguments;
- CHECK(!CommandLine::ParseArguments(input, arguments));
- CHECK(arguments.Count() == 1);
- CHECK(arguments[0].Compare(StringAnsi("word")) == 0);
- }
- SECTION("Quotes at the beginning of the word")
- {
- String input("start\"word\"");
- Array arguments;
- CHECK(!CommandLine::ParseArguments(input, arguments));
- CHECK(arguments.Count() == 1);
- CHECK(arguments[0].Compare(StringAnsi("start\"word\"")) == 0);
- }
- SECTION("Quotes in the middle of the word")
- {
- String input("start\"word\"end");
- Array arguments;
- CHECK(!CommandLine::ParseArguments(input, arguments));
- CHECK(arguments.Count() == 1);
- CHECK(arguments[0].Compare(StringAnsi("start\"word\"end")) == 0);
- }
- SECTION("Quotes at the end of the word")
- {
- String input("\"word\"end");
- Array arguments;
- CHECK(!CommandLine::ParseArguments(input, arguments));
- CHECK(arguments.Count() == 1);
- CHECK(arguments[0].Compare(StringAnsi("\"word\"end")) == 0);
- }
- SECTION("Multiple words")
- {
- String input("The quick brown fox");
- Array arguments;
- CHECK(!CommandLine::ParseArguments(input, arguments));
- CHECK(arguments.Count() == 4);
- CHECK(arguments[0].Compare(StringAnsi("The")) == 0);
- CHECK(arguments[1].Compare(StringAnsi("quick")) == 0);
- CHECK(arguments[2].Compare(StringAnsi("brown")) == 0);
- CHECK(arguments[3].Compare(StringAnsi("fox")) == 0);
- }
- SECTION("Multiple words with quotes")
- {
- String input("The \"quick brown fox\" jumps over the \"lazy\" dog");
- Array arguments;
- CHECK(!CommandLine::ParseArguments(input, arguments));
- CHECK(arguments.Count() == 7);
- CHECK(arguments[0].Compare(StringAnsi("The")) == 0);
- CHECK(arguments[1].Compare(StringAnsi("quick brown fox")) == 0);
- CHECK(arguments[2].Compare(StringAnsi("jumps")) == 0);
- CHECK(arguments[3].Compare(StringAnsi("over")) == 0);
- CHECK(arguments[4].Compare(StringAnsi("the")) == 0);
- CHECK(arguments[5].Compare(StringAnsi("lazy")) == 0);
- CHECK(arguments[6].Compare(StringAnsi("dog")) == 0);
- }
- SECTION("Flax.Build sample parameters")
- {
- String input("-log -mutex -workspace=\"C:\\path with spaces/to/FlaxEngine/\" -configuration=Debug -hotreload=\".HotReload.1\"");
- Array arguments;
- CHECK(!CommandLine::ParseArguments(input, arguments));
- CHECK(arguments.Count() == 5);
- CHECK(arguments[0].Compare(StringAnsi("-log")) == 0);
- CHECK(arguments[1].Compare(StringAnsi("-mutex")) == 0);
- CHECK(arguments[2].Compare(StringAnsi("-workspace=\"C:\\path with spaces/to/FlaxEngine/\"")) == 0);
- CHECK(arguments[3].Compare(StringAnsi("-configuration=Debug")) == 0);
- CHECK(arguments[4].Compare(StringAnsi("-hotreload=\".HotReload.1\"")) == 0);
- }
- }
-}
diff --git a/Source/Tools/Flax.Build/CommandLine.cs b/Source/Tools/Flax.Build/CommandLine.cs
index bc54675f5..523134618 100644
--- a/Source/Tools/Flax.Build/CommandLine.cs
+++ b/Source/Tools/Flax.Build/CommandLine.cs
@@ -266,6 +266,8 @@ namespace Flax.Build
int nameStart = i;
while (i < length && commandLine[i] != '-' && commandLine[i] != '=' && !char.IsWhiteSpace(commandLine[i]))
i++;
+ if (wholeQuote)
+ i--;
int nameEnd = i;
string name = commandLine.Substring(nameStart, nameEnd - nameStart);