diff --git a/Source/Licensing/LicenseKey.Test.cs b/Source/Licensing/LicenseKey.Test.cs
index a8bbc47..d4d6316 100644
--- a/Source/Licensing/LicenseKey.Test.cs
+++ b/Source/Licensing/LicenseKey.Test.cs
@@ -37,7 +37,6 @@ namespace Nuclex.Support.Licensing {
new LicenseKey();
}
-
/// Validates the correct translation of keys to GUIDs and back
[Test]
public void TestGuidKeyConversion() {
diff --git a/Source/Parsing/CommandLine.Argument.cs b/Source/Parsing/CommandLine.Argument.cs
index 1b7a914..2391393 100644
--- a/Source/Parsing/CommandLine.Argument.cs
+++ b/Source/Parsing/CommandLine.Argument.cs
@@ -140,6 +140,11 @@ namespace Nuclex.Support.Parsing {
}
}
+ /// The raw length of the command line argument
+ internal int RawLength {
+ get { return this.raw.Count; }
+ }
+
///
/// Contains the entire option as it was specified on the command line
///
diff --git a/Source/Parsing/CommandLine.Formatter.cs b/Source/Parsing/CommandLine.Formatter.cs
index a654353..079dc96 100644
--- a/Source/Parsing/CommandLine.Formatter.cs
+++ b/Source/Parsing/CommandLine.Formatter.cs
@@ -20,12 +20,43 @@ License along with this library
using System;
using System.Collections.Generic;
+using System.Text;
namespace Nuclex.Support.Parsing {
partial class CommandLine {
- internal static class Formatter { }
+ /// Formats a command line instance into a string
+ internal static class Formatter {
+
+ ///
+ /// Formats all arguments in the provided command line instance into a string
+ ///
+ /// Command line instance that will be formatted
+ /// All arguments in the command line instance as a string
+ public static string FormatCommandLine(CommandLine commandLine) {
+ int totalLength = 0;
+ for(int index = 0; index < commandLine.arguments.Count; ++index) {
+ if(index != 0) {
+ ++totalLength; // For spacing between arguments
+ }
+
+ totalLength += commandLine.arguments[index].RawLength;
+ }
+
+ StringBuilder builder = new StringBuilder(totalLength);
+ for(int index = 0; index < commandLine.arguments.Count; ++index) {
+ if(index != 0) {
+ builder.Append(' ');
+ }
+
+ builder.Append(commandLine.arguments[index].Raw);
+ }
+
+ return builder.ToString();
+ }
+
+ }
}
diff --git a/Source/Parsing/CommandLine.Parser.cs b/Source/Parsing/CommandLine.Parser.cs
index cfd6438..7de3763 100644
--- a/Source/Parsing/CommandLine.Parser.cs
+++ b/Source/Parsing/CommandLine.Parser.cs
@@ -49,20 +49,6 @@ namespace Nuclex.Support.Parsing {
return theParser.arguments;
}
-#if ENABLE_TOKENIZED_COMMAND_LINE_PARSING // don't enable, it's broken!
- /// Parses a string containing command line arguments
- /// Command line tokens that will be parsed
- /// Whether the / character initiates an argument
- /// The parsed command line arguments from the string
- public static List Parse(
- string[] commandLineArguments, bool windowsMode
- ) {
- Parser theParser = new Parser(windowsMode);
- theParser.parseSplitCommandLine(commandLineArguments);
- return theParser.arguments;
- }
-#endif // ENABLE_TOKENIZED_COMMAND_LINE_PARSING
-
///
/// Parses the provided string and adds the parameters found to
/// the command line representation
@@ -94,31 +80,6 @@ namespace Nuclex.Support.Parsing {
}
}
-#if ENABLE_TOKENIZED_COMMAND_LINE_PARSING // don't enable, it's broken!
- ///
- /// Parses the command line from a series pre-split argument tokens
- ///
- /// Split argument tokens that will be parsed
- private void parseSplitCommandLine(string[] commandLineParts) {
- if(commandLineParts == null) {
- return;
- }
-
- // Walk through the command line character by character and gather
- // the parameters and values to build the command line representation from
- for(int index = 0; index < commandLineParts.Length; ++index) {
-
- if(commandLineParts[index] != null) {
- int characterIndex = 0;
- parseChunk(commandLineParts[index], ref characterIndex);
-
- Debug.Assert(characterIndex == commandLineParts[index].Length);
- }
-
- }
- }
-#endif // ENABLE_TOKENIZED_COMMAND_LINE_PARSING
-
///
/// Parses a chunk of characters and adds it as an option or a loose value to
/// the command line representation we're building
diff --git a/Source/Parsing/CommandLine.Test.cs b/Source/Parsing/CommandLine.Test.cs
index c53a38e..3e4e440 100644
--- a/Source/Parsing/CommandLine.Test.cs
+++ b/Source/Parsing/CommandLine.Test.cs
@@ -579,8 +579,52 @@ namespace Nuclex.Support.Parsing {
Assert.IsFalse(test.HasArgument("fourth"));
}
+ ///
+ /// Tests whether a command line can be built with the command line class
+ ///
+ [Test]
+ public void TestCommandLineFormatting() {
+ CommandLine commandLine = new CommandLine();
+
+ commandLine.AddValue("single");
+ commandLine.AddValue("with space");
+ commandLine.AddOption("option");
+ commandLine.AddOption("@@", "extravagant-option");
+ commandLine.AddAssignment("name", "value");
+ commandLine.AddAssignment("name", "value with spaces");
+ commandLine.AddAssignment("@@", "name", "value");
+ commandLine.AddAssignment("@@", "name", "value with spaces");
+
+ Assert.AreEqual(8, commandLine.Arguments.Count);
+ Assert.AreEqual("single", commandLine.Arguments[0].Value);
+ Assert.AreEqual("with space", commandLine.Arguments[1].Value);
+ Assert.AreEqual("option", commandLine.Arguments[2].Name);
+ Assert.AreEqual("@@", commandLine.Arguments[3].Initiator);
+ Assert.AreEqual("extravagant-option", commandLine.Arguments[3].Name);
+ Assert.AreEqual("name", commandLine.Arguments[4].Name);
+ Assert.AreEqual("value", commandLine.Arguments[4].Value);
+ Assert.AreEqual("name", commandLine.Arguments[5].Name);
+ Assert.AreEqual("value with spaces", commandLine.Arguments[5].Value);
+ Assert.AreEqual("@@", commandLine.Arguments[6].Initiator);
+ Assert.AreEqual("name", commandLine.Arguments[6].Name);
+ Assert.AreEqual("value", commandLine.Arguments[6].Value);
+ Assert.AreEqual("name", commandLine.Arguments[7].Name);
+ Assert.AreEqual("@@", commandLine.Arguments[7].Initiator);
+ Assert.AreEqual("value with spaces", commandLine.Arguments[7].Value);
+
+ string commandLineString = commandLine.ToString();
+ Assert.AreEqual(
+ "single \"with space\" " +
+ "-option @@extravagant-option " +
+ "-name=value -name=\"value with spaces\" " +
+ "@@name=value @@name=\"value with spaces\"",
+ commandLineString
+ );
+
+ }
+
}
} // namespace Nuclex.Support.Parsing
-#endif // UNITTEST
\ No newline at end of file
+#endif // UNITTEST
diff --git a/Source/Parsing/CommandLine.cs b/Source/Parsing/CommandLine.cs
index 51f7d9e..0e9d45a 100644
--- a/Source/Parsing/CommandLine.cs
+++ b/Source/Parsing/CommandLine.cs
@@ -91,26 +91,6 @@ namespace Nuclex.Support.Parsing {
this.arguments = argumentList;
}
-#if ENABLE_TOKENIZED_COMMAND_LINE_PARSING // don't enable, it's broken!
- /// Parses the command line arguments from the provided string
- /// Command line tokens that will be parsed
- /// The parsed command line
- public static CommandLine Parse(string[] commandLineArguments) {
- bool windowsMode = (Path.DirectorySeparatorChar != '/');
- return Parse(commandLineArguments, windowsMode);
- }
-
- /// Parses the command line arguments from the provided string
- /// Command line tokens that will be parsed
- /// Whether the / character initiates an argument
- /// The parsed command line
- public static CommandLine Parse(string[] commandLineArguments, bool windowsMode) {
- return new CommandLine(
- Parser.Parse(commandLineArguments, windowsMode)
- );
- }
-#endif // ENABLE_TOKENIZED_COMMAND_LINE_PARSING
-
/// Parses the command line arguments from the provided string
/// String containing the command line arguments
/// The parsed command line
@@ -146,41 +126,101 @@ namespace Nuclex.Support.Parsing {
return (indexOfArgument(name) != -1);
}
-#if false
- /// Retrieves the value of the specified argument
- /// Name of the argument whose value will be retrieved
- /// The value of the specified argument
- public string GetValue(string name) {
- int index = indexOfArgument(name);
- if(index == -1) {
- return null;
+ /// Adds a value to the command line
+ /// Value that will be added
+ public void AddValue(string value) {
+ bool valueContainsSpaces = (value.IndexOfAny(new char[] { ' ', '\t' }) != -1);
+
+ if(valueContainsSpaces) {
+ StringBuilder builder = new StringBuilder(value.Length + 2);
+ builder.Append('"');
+ builder.Append(value);
+ builder.Append('"');
+
+ this.arguments.Add(
+ Argument.ValueOnly(
+ new StringSegment(builder.ToString(), 0, value.Length + 2),
+ 1,
+ value.Length
+ )
+ );
+ } else {
+ this.arguments.Add(
+ Argument.ValueOnly(new StringSegment(value), 0, value.Length)
+ );
}
-
- // Does this argument have a value?
- Argument argument = this.arguments[index];
- if(argument.Value != null) {
- return argument.Value;
- } else { // No, it might be a spaced argument
-
- // See if anything more follows this argument
- ++index;
- if(index < this.arguments.Count) {
-
- // If something follows the argument, and it is not an option of its own,
- // use its value as the value for the preceding argument
- argument = this.arguments[index];
- if(argument.Name == null) {
- return argument.Value;
- }
-
- }
-
- }
-
- // No argument found
- return null;
}
-#endif
+
+ /// Adds an option to the command line
+ /// Name of the option that will be added
+ public void AddOption(string name) {
+ AddOption("-", name);
+ }
+
+ /// Adds an option to the command line
+ /// Initiator that will be used to start the option
+ /// Name of the option that will be added
+ public void AddOption(string initiator, string name) {
+ StringBuilder builder = new StringBuilder(
+ initiator.Length + name.Length
+ );
+ builder.Append(initiator);
+ builder.Append(name);
+
+ this.arguments.Add(
+ Argument.OptionOnly(
+ new StringSegment(builder.ToString()),
+ initiator.Length,
+ name.Length
+ )
+ );
+ }
+
+ /// Adds an option with an assignment to the command line
+ /// Name of the option that will be added
+ /// Value that will be assigned to the option
+ public void AddAssignment(string name, string value) {
+ AddAssignment("-", name, value);
+ }
+
+ /// Adds an option with an assignment to the command line
+ /// Initiator that will be used to start the option
+ /// Name of the option that will be added
+ /// Value that will be assigned to the option
+ public void AddAssignment(string initiator, string name, string value) {
+ bool valueContainsSpaces = (value.IndexOfAny(new char[] { ' ', '\t' }) != -1);
+ StringBuilder builder = new StringBuilder(
+ initiator.Length + name.Length + 1 + value.Length +
+ (valueContainsSpaces ? 2 : 0)
+ );
+ builder.Append(initiator);
+ builder.Append(name);
+ builder.Append('=');
+ if(valueContainsSpaces) {
+ builder.Append('"');
+ builder.Append(value);
+ builder.Append('"');
+ } else {
+ builder.Append(value);
+ }
+
+ this.arguments.Add(
+ new Argument(
+ new StringSegment(builder.ToString()),
+ initiator.Length,
+ name.Length,
+ initiator.Length + name.Length + 1 +
+ (valueContainsSpaces ? 1 : 0),
+ value.Length
+ )
+ );
+ }
+
+ /// Returns a string that contains the entire command line
+ /// The entire command line as a single string
+ public override string ToString() {
+ return Formatter.FormatCommandLine(this);
+ }
/// Retrieves the index of the argument with the specified name
/// Name of the argument whose index will be returned
@@ -197,7 +237,6 @@ namespace Nuclex.Support.Parsing {
return -1;
}
-
/// Options that were specified on the command line
public IList Arguments {
get { return this.arguments; }