Removed the old command line parser since its replacement is fully functional by now; the CommandLine class now provides a HasArgument() method for convenience; added experimental parsing for pre-split command lines (as provided by .NET's Main() method) and disabled it because it turned out to be a bad idea
git-svn-id: file:///srv/devel/repo-conversion/nusu@130 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
parent
47b0039137
commit
a2331b95c1
|
@ -157,10 +157,6 @@
|
|||
<Compile Include="Source\Parsing\CommandLine.Test.cs">
|
||||
<DependentUpon>CommandLine.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Parsing\BrokenCommandLineParser.cs" />
|
||||
<Compile Include="Source\Parsing\BrokenCommandLineParser.Test.cs">
|
||||
<DependentUpon>BrokenCommandLineParser.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Parsing\CommandLine.cs" />
|
||||
<Compile Include="Source\Parsing\CommandLine.Parser.cs">
|
||||
<DependentUpon>CommandLine.cs</DependentUpon>
|
||||
|
|
|
@ -139,10 +139,6 @@
|
|||
<Compile Include="Source\Parsing\CommandLine.Test.cs">
|
||||
<DependentUpon>CommandLine.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Parsing\BrokenCommandLineParser.cs" />
|
||||
<Compile Include="Source\Parsing\BrokenCommandLineParser.Test.cs">
|
||||
<DependentUpon>BrokenCommandLineParser.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Parsing\CommandLine.cs" />
|
||||
<Compile Include="Source\Parsing\CommandLine.Parser.cs">
|
||||
<DependentUpon>CommandLine.cs</DependentUpon>
|
||||
|
|
|
@ -1,147 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
#if UNITTEST
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
#if ENABLE_BROKEN_COMMAND_LINE_PARSER // Too bugged. 100% test coverage not possible.
|
||||
|
||||
namespace Nuclex.Support.Parsing {
|
||||
|
||||
/// <summary>Ensures that the command line parser is working properly</summary>
|
||||
[TestFixture]
|
||||
public class CommandLineParserTest {
|
||||
|
||||
/// <summary>Validates that normal arguments can be parsed</summary>
|
||||
[Test]
|
||||
public void TestArrayConstructorWithPlainArguments() {
|
||||
Assert.IsTrue(
|
||||
new CommandLineParser(new string[] { "-hello" }).HasArgument("hello"),
|
||||
"Argument with minus sign is recognized"
|
||||
);
|
||||
Assert.IsTrue(
|
||||
new CommandLineParser(new string[] { "--hello" }).HasArgument("hello"),
|
||||
"Argument with double minus sign is recognized"
|
||||
);
|
||||
Assert.IsTrue(
|
||||
new CommandLineParser(new string[] { "/hello" }).HasArgument("hello"),
|
||||
"Argument with slash is recognized"
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>Validates that argument assignments are working</summary>
|
||||
[Test]
|
||||
public void TestArrayConstructorWithAssignments() {
|
||||
Assert.AreEqual(
|
||||
"world",
|
||||
new CommandLineParser(new string[] { "-hello:world" })["hello"],
|
||||
"Argument can be assigned with a double colon"
|
||||
);
|
||||
Assert.AreEqual(
|
||||
"world",
|
||||
new CommandLineParser(new string[] { "-hello=world" })["hello"],
|
||||
"Argument can be assigned with a equality sign"
|
||||
);
|
||||
Assert.AreEqual(
|
||||
"world",
|
||||
new CommandLineParser(new string[] { "-hello", "world" })["hello"],
|
||||
"Argument can be assigned with a space"
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that loosely specified values are recognized by the parser
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestArrayConstructorWithLooseValues() {
|
||||
Assert.IsTrue(
|
||||
new CommandLineParser(new string[] { "hello" }).Values.Contains("hello"),
|
||||
"Plain loose value is recognized"
|
||||
);
|
||||
Assert.IsTrue(
|
||||
new CommandLineParser(new string[] { "-hello:world", "foo" }).Values.Contains("foo"),
|
||||
"Loose value following an assignment is recognized"
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the parser can parse the processes current command line if
|
||||
/// the default constructor is used
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestDefaultConstructor() {
|
||||
new CommandLineParser();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the string constructor works for simple arguments being
|
||||
/// specified on the command line
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestStringConstructorWithSimpleArguments() {
|
||||
CommandLineParser parser = new CommandLineParser("argument1 argument2");
|
||||
Assert.AreEqual("argument1", parser.Values[0]);
|
||||
Assert.AreEqual("argument2", parser.Values[1]);
|
||||
}
|
||||
|
||||
// TODO: This test fails!!
|
||||
#if FAILED_TEST
|
||||
/// <summary>
|
||||
/// Bullshit
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestStringConstructorWithQuotedArguments() {
|
||||
CommandLineParser parser = new CommandLineParser("\"this is a single argument\"");
|
||||
Assert.AreEqual("this is a single argument", parser.Values[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the string constructor recognizes an unfinished argument
|
||||
/// (that is, an argument that gets 'nothing' assigned)
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestStringConstructorWithUnfinishedAssignment() {
|
||||
CommandLineParser parser = new CommandLineParser("--hello= --world=");
|
||||
Assert.AreEqual(0, parser.Values.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the string constructor recognizes an argument with a space before
|
||||
/// its assigned value
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestStringConstructorWithSpacedAssignment() {
|
||||
CommandLineParser parser = new CommandLineParser("--hello= world");
|
||||
Assert.AreEqual(1, parser.Values.Count);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Parsing
|
||||
|
||||
#endif // ENABLE_BROKEN_COMMAND_LINE_PARSER
|
||||
|
||||
#endif // UNITTEST
|
|
@ -1,185 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2009 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Specialized;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
#if ENABLE_BROKEN_COMMAND_LINE_PARSER // Too bugged. 100% test coverage not possible.
|
||||
|
||||
namespace Nuclex.Support.Parsing {
|
||||
|
||||
/// <summary>Parses an application's command line</summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Based on an article Richard Lopes published on "The Code Project" at
|
||||
/// http://www.codeproject.com/csharp/command_line.asp
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Valid forms for command line arguments: {-|/|--}param[{ |=|:}[{"|'}]value[{"|'}]]
|
||||
/// </para>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// -param1 value1
|
||||
/// --param2
|
||||
/// /param3:"Test-:-work"
|
||||
/// /param4=happy
|
||||
/// -param5 '--=nice=--'
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public class CommandLineParser {
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new command line parser using the running program's command line
|
||||
/// </summary>
|
||||
public CommandLineParser() : this(System.Environment.CommandLine) { }
|
||||
|
||||
/// <summary>Initializes a new command line parser</summary>
|
||||
/// <param name="arguments">All supplied command line arguments as a single string</param>
|
||||
public CommandLineParser(string arguments)
|
||||
: this(arguments.Split(new char[] { ' ', '\t' })) { }
|
||||
|
||||
/// <summary>Initializes a new command line parser</summary>
|
||||
/// <param name="arguments">Arguments that have been passed in the command line</param>
|
||||
public CommandLineParser(string[] arguments) {
|
||||
this.arguments = new StringDictionary();
|
||||
this.values = new StringCollection();
|
||||
|
||||
string activeParameter = null;
|
||||
|
||||
foreach(string argument in arguments) {
|
||||
|
||||
// Look for arguments ('-', '/', '--') with their assignments ('=', ':')
|
||||
string[] parts = splitter.Split(argument, 3);
|
||||
switch(parts.Length) {
|
||||
|
||||
// Value found without an argument being specified (eg. file name)
|
||||
case 1: {
|
||||
|
||||
if(activeParameter != null) {
|
||||
if(!this.arguments.ContainsKey(activeParameter)) {
|
||||
parts[0] = remover.Replace(parts[0], "$1");
|
||||
this.arguments.Add(activeParameter, parts[0]);
|
||||
}
|
||||
activeParameter = null;
|
||||
} else {
|
||||
this.values.Add(parts[0]);
|
||||
}
|
||||
|
||||
// Error: No argument is waiting for a value. Skip this argument.
|
||||
break;
|
||||
}
|
||||
|
||||
// Found an argument with no value assignment
|
||||
case 2: {
|
||||
|
||||
// In case the previous argument is still waiting for a value we need to finish
|
||||
// it up before switching to the argument we just found.
|
||||
if(activeParameter != null)
|
||||
if(!this.arguments.ContainsKey(activeParameter))
|
||||
this.arguments.Add(activeParameter, null);
|
||||
|
||||
// Remember argument to allow for a later value assignment
|
||||
activeParameter = parts[1];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Found an argument with a proper assignment declaration
|
||||
case 3: {
|
||||
|
||||
// In case the previous argument is still waiting for a value we need to finish
|
||||
// it up before switching to the argument we just found.
|
||||
if(activeParameter != null)
|
||||
if(!this.arguments.ContainsKey(activeParameter))
|
||||
this.arguments.Add(activeParameter, null);
|
||||
|
||||
activeParameter = parts[1];
|
||||
|
||||
// Remove any quotes that might be enclosing this argument (",')
|
||||
if(!this.arguments.ContainsKey(activeParameter)) {
|
||||
parts[2] = remover.Replace(parts[2], "$1");
|
||||
this.arguments.Add(activeParameter, parts[2]);
|
||||
}
|
||||
|
||||
activeParameter = null;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In case the previous argument is still waiting for a value we need to finish
|
||||
// it up before leaving the parsing method.
|
||||
if(activeParameter != null) {
|
||||
if(!this.arguments.ContainsKey(activeParameter)) {
|
||||
this.arguments.Add(activeParameter, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Returns the value of an argument by the argument's name</summary>
|
||||
/// <param name="argumentName">Name of the argument whose value will be returned</param>
|
||||
/// <returns>The value of the argument with the specified name</returns>
|
||||
public string this[string argumentName] {
|
||||
get { return this.arguments[argumentName]; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the specified argument was specified on the command line
|
||||
/// </summary>
|
||||
/// <param name="argumentName">Name of the argument to check</param>
|
||||
/// <returns>True if the specified command was given on the command line</returns>
|
||||
public bool HasArgument(string argumentName) {
|
||||
return this.arguments.ContainsKey(argumentName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Any values loosely specified on the command line without being assigned
|
||||
/// to an argument.
|
||||
/// </summary>
|
||||
public StringCollection Values {
|
||||
get { return this.values; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Regular Expression used to split the arguments and their assigned values
|
||||
/// </summary>
|
||||
private static Regex splitter =
|
||||
new Regex(@"^-{1,2}|^/|=|:", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
|
||||
/// <summary>
|
||||
/// Regular Expression used to remove quotations around an argument's value
|
||||
/// </summary>
|
||||
private static Regex remover =
|
||||
new Regex(@"^['""]?(.*?)['""]?$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
|
||||
/// <summary>Stores the parsed arguments</summary>
|
||||
private StringDictionary arguments;
|
||||
/// <summary>
|
||||
/// Stores any values passed on the command line without assigning an argument
|
||||
/// </summary>
|
||||
private StringCollection values;
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Parsing
|
||||
|
||||
#endif // ENABLE_BROKEN_COMMAND_LINE_PARSER
|
|
@ -34,20 +34,35 @@ namespace Nuclex.Support.Parsing {
|
|||
/// <param name="windowsMode">Whether the / character initiates an argument</param>
|
||||
private Parser(bool windowsMode) {
|
||||
this.windowsMode = windowsMode;
|
||||
this.commandLine = new CommandLine();
|
||||
this.arguments = new List<CommandLine.Argument>();
|
||||
}
|
||||
|
||||
/// <summary>Parses a string containing command line arguments</summary>
|
||||
/// <param name="commandLineString">String that will be parsed</param>
|
||||
/// <param name="windowsMode">Whether the / character initiates an argument</param>
|
||||
/// <returns>The parsed command line arguments from the string</returns>
|
||||
public static CommandLine Parse(string commandLineString, bool windowsMode) {
|
||||
Console.WriteLine("Parsing '" + commandLineString + "'");
|
||||
public static List<CommandLine.Argument> Parse(
|
||||
string commandLineString, bool windowsMode
|
||||
) {
|
||||
Parser theParser = new Parser(windowsMode);
|
||||
theParser.parseFullCommandLine(commandLineString);
|
||||
return theParser.commandLine;
|
||||
return theParser.arguments;
|
||||
}
|
||||
|
||||
#if ENABLE_TOKENIZED_COMMAND_LINE_PARSING // don't enable, it's broken!
|
||||
/// <summary>Parses a string containing command line arguments</summary>
|
||||
/// <param name="commandLineArguments">Command line tokens that will be parsed</param>
|
||||
/// <param name="windowsMode">Whether the / character initiates an argument</param>
|
||||
/// <returns>The parsed command line arguments from the string</returns>
|
||||
public static List<CommandLine.Argument> Parse(
|
||||
string[] commandLineArguments, bool windowsMode
|
||||
) {
|
||||
Parser theParser = new Parser(windowsMode);
|
||||
theParser.parseSplitCommandLine(commandLineArguments);
|
||||
return theParser.arguments;
|
||||
}
|
||||
#endif // ENABLE_TOKENIZED_COMMAND_LINE_PARSING
|
||||
|
||||
/// <summary>
|
||||
/// Parses the provided string and adds the parameters found to
|
||||
/// the command line representation
|
||||
|
@ -79,6 +94,31 @@ namespace Nuclex.Support.Parsing {
|
|||
}
|
||||
}
|
||||
|
||||
#if ENABLE_TOKENIZED_COMMAND_LINE_PARSING // don't enable, it's broken!
|
||||
/// <summary>
|
||||
/// Parses the command line from a series pre-split argument tokens
|
||||
/// </summary>
|
||||
/// <param name="commandLineParts">Split argument tokens that will be parsed</param>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// Parses a chunk of characters and adds it as an option or a loose value to
|
||||
/// the command line representation we're building
|
||||
|
@ -100,7 +140,7 @@ namespace Nuclex.Support.Parsing {
|
|||
|
||||
// Does the string end here? Stop parsing.
|
||||
if(index >= commandLineString.Length) {
|
||||
this.commandLine.addValue(new StringSegment(commandLineString, startIndex, 1));
|
||||
addValue(new StringSegment(commandLineString, startIndex, 1));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -153,12 +193,12 @@ namespace Nuclex.Support.Parsing {
|
|||
/// </param>
|
||||
/// <returns>The number of characters consumed</returns>
|
||||
private void parsePotentialOption(
|
||||
string commandLineString, int initiatorStartIndex, ref int index
|
||||
string commandLineString, int initiatorStartIndex, ref int index
|
||||
) {
|
||||
|
||||
// If the string ends here this can only be considered as a loose value
|
||||
if(index == commandLineString.Length) {
|
||||
this.commandLine.addValue(
|
||||
addValue(
|
||||
new StringSegment(
|
||||
commandLineString,
|
||||
initiatorStartIndex,
|
||||
|
@ -187,7 +227,7 @@ namespace Nuclex.Support.Parsing {
|
|||
index = commandLineString.Length;
|
||||
}
|
||||
|
||||
commandLine.addValue(
|
||||
addValue(
|
||||
new StringSegment(
|
||||
commandLineString, initiatorStartIndex, index - initiatorStartIndex
|
||||
)
|
||||
|
@ -211,7 +251,7 @@ namespace Nuclex.Support.Parsing {
|
|||
/// </param>
|
||||
/// <param name="index">Index at which the option name ended</param>
|
||||
private void parsePotentialOptionAssignment(
|
||||
string commandLineString, int initiatorStartIndex, int nameStartIndex, ref int index
|
||||
string commandLineString, int initiatorStartIndex, int nameStartIndex, ref int index
|
||||
) {
|
||||
int nameEndIndex = index;
|
||||
int valueStartIndex;
|
||||
|
@ -245,7 +285,7 @@ namespace Nuclex.Support.Parsing {
|
|||
}
|
||||
|
||||
int argumentLength = index - initiatorStartIndex;
|
||||
this.commandLine.addArgument(
|
||||
this.arguments.Add(
|
||||
new Argument(
|
||||
new StringSegment(commandLineString, initiatorStartIndex, argumentLength),
|
||||
nameStartIndex, nameEndIndex - nameStartIndex,
|
||||
|
@ -264,7 +304,7 @@ namespace Nuclex.Support.Parsing {
|
|||
/// </param>
|
||||
/// <param name="index">Index at which the option name ended</param>
|
||||
private void parseOptionValue(
|
||||
string commandLineString, int initiatorStartIndex, int nameStartIndex, ref int index
|
||||
string commandLineString, int initiatorStartIndex, int nameStartIndex, ref int index
|
||||
) {
|
||||
int nameEndIndex = index - 1;
|
||||
int valueStartIndex, valueEndIndex;
|
||||
|
@ -308,7 +348,7 @@ namespace Nuclex.Support.Parsing {
|
|||
}
|
||||
|
||||
int argumentLength = index - initiatorStartIndex;
|
||||
this.commandLine.addArgument(
|
||||
this.arguments.Add(
|
||||
new Argument(
|
||||
new StringSegment(commandLineString, initiatorStartIndex, argumentLength),
|
||||
nameStartIndex, nameEndIndex - nameStartIndex,
|
||||
|
@ -329,14 +369,14 @@ namespace Nuclex.Support.Parsing {
|
|||
index = commandLineString.IndexOf(quoteCharacter, valueIndex);
|
||||
if(index == -1) {
|
||||
index = commandLineString.Length; // value ends at string end
|
||||
commandLine.addArgument(
|
||||
this.arguments.Add(
|
||||
Argument.ValueOnly(
|
||||
new StringSegment(commandLineString, startIndex, index - startIndex),
|
||||
valueIndex, index - valueIndex
|
||||
)
|
||||
);
|
||||
} else { // A closing quote was found
|
||||
commandLine.addArgument(
|
||||
this.arguments.Add(
|
||||
Argument.ValueOnly(
|
||||
new StringSegment(commandLineString, startIndex, index - startIndex + 1),
|
||||
valueIndex, index - valueIndex
|
||||
|
@ -357,8 +397,14 @@ namespace Nuclex.Support.Parsing {
|
|||
index = commandLineString.Length;
|
||||
}
|
||||
|
||||
commandLine.addValue(
|
||||
new StringSegment(commandLineString, startIndex, index - startIndex)
|
||||
addValue(new StringSegment(commandLineString, startIndex, index - startIndex));
|
||||
}
|
||||
|
||||
/// <summary>Adds a loose value to the command line</summary>
|
||||
/// <param name="value">Value taht will be added</param>
|
||||
private void addValue(StringSegment value) {
|
||||
this.arguments.Add(
|
||||
Argument.ValueOnly(value, value.Offset, value.Count)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -383,8 +429,8 @@ namespace Nuclex.Support.Parsing {
|
|||
/// <summary>Characters the parser considers to be whitespace</summary>
|
||||
private static readonly char[] WhitespaceCharacters = new char[] { ' ', '\t' };
|
||||
|
||||
/// <summary>Command line currently being built by the parser</summary>
|
||||
private CommandLine commandLine;
|
||||
/// <summary>Argument list being filled by the parser</summary>
|
||||
private List<CommandLine.Argument> arguments;
|
||||
/// <summary>Whether the '/' character initiates an argument</summary>
|
||||
private bool windowsMode;
|
||||
|
||||
|
|
|
@ -194,6 +194,14 @@ namespace Nuclex.Support.Parsing {
|
|||
|
||||
#endregion // class ArgumentTest
|
||||
|
||||
/// <summary>Verifies that the default constructor is working</summary>
|
||||
[Test]
|
||||
public void TestDefaultConstructor() {
|
||||
CommandLine commandLine = new CommandLine();
|
||||
|
||||
Assert.AreEqual(0, commandLine.Arguments.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that the parser can handle an argument initiator with an
|
||||
/// assignment that is missing a name
|
||||
|
@ -302,7 +310,7 @@ namespace Nuclex.Support.Parsing {
|
|||
/// <summary>Validates that null can be parsed</summary>
|
||||
[Test]
|
||||
public void TestParseNull() {
|
||||
CommandLine commandLine = CommandLine.Parse(null);
|
||||
CommandLine commandLine = CommandLine.Parse((string)null);
|
||||
|
||||
Assert.AreEqual(0, commandLine.Arguments.Count);
|
||||
}
|
||||
|
@ -558,6 +566,19 @@ namespace Nuclex.Support.Parsing {
|
|||
Assert.AreEqual("//world", commandLine.Arguments[1].Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the existence of named arguments can be checked
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestHasArgument() {
|
||||
CommandLine test = CommandLine.Parse("/first:x /second:y /second:z third");
|
||||
|
||||
Assert.IsTrue(test.HasArgument("first"));
|
||||
Assert.IsTrue(test.HasArgument("second"));
|
||||
Assert.IsFalse(test.HasArgument("third"));
|
||||
Assert.IsFalse(test.HasArgument("fourth"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Parsing
|
||||
|
|
|
@ -21,6 +21,7 @@ License along with this library
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using Nuclex.Support.Collections;
|
||||
|
||||
|
@ -82,55 +83,120 @@ namespace Nuclex.Support.Parsing {
|
|||
public partial class CommandLine {
|
||||
|
||||
/// <summary>Initializes a new command line</summary>
|
||||
public CommandLine() {
|
||||
this.arguments = new List<Argument>();
|
||||
public CommandLine() : this(new List<Argument>()) { }
|
||||
|
||||
/// <summary>Initializes a new command line</summary>
|
||||
/// <param name="argumentList">List containing the parsed arguments</param>
|
||||
private CommandLine(List<Argument> argumentList) {
|
||||
this.arguments = argumentList;
|
||||
}
|
||||
|
||||
#if ENABLE_TOKENIZED_COMMAND_LINE_PARSING // don't enable, it's broken!
|
||||
/// <summary>Parses the command line arguments from the provided string</summary>
|
||||
/// <param name="commandLineArguments">Command line tokens that will be parsed</param>
|
||||
/// <returns>The parsed command line</returns>
|
||||
public static CommandLine Parse(string[] commandLineArguments) {
|
||||
bool windowsMode = (Path.DirectorySeparatorChar != '/');
|
||||
return Parse(commandLineArguments, windowsMode);
|
||||
}
|
||||
|
||||
/// <summary>Parses the command line arguments from the provided string</summary>
|
||||
/// <param name="commandLineArguments">Command line tokens that will be parsed</param>
|
||||
/// <param name="windowsMode">Whether the / character initiates an argument</param>
|
||||
/// <returns>The parsed command line</returns>
|
||||
public static CommandLine Parse(string[] commandLineArguments, bool windowsMode) {
|
||||
return new CommandLine(
|
||||
Parser.Parse(commandLineArguments, windowsMode)
|
||||
);
|
||||
}
|
||||
#endif // ENABLE_TOKENIZED_COMMAND_LINE_PARSING
|
||||
|
||||
/// <summary>Parses the command line arguments from the provided string</summary>
|
||||
/// <param name="commandLineString">String containing the command line arguments</param>
|
||||
/// <returns>The parsed command line</returns>
|
||||
/// <remarks>
|
||||
/// You should always pass Environment.CommandLine to this methods to avoid
|
||||
/// some problems with the build-in command line tokenizer in .NET
|
||||
/// (which splits '--test"hello world"/v' into '--testhello world/v')
|
||||
/// </remarks>
|
||||
public static CommandLine Parse(string commandLineString) {
|
||||
bool windowsMode = (Path.DirectorySeparatorChar != '/');
|
||||
return Parser.Parse(commandLineString, windowsMode);
|
||||
return Parse(commandLineString, windowsMode);
|
||||
}
|
||||
|
||||
/// <summary>Parses the command line arguments from the provided string</summary>
|
||||
/// <param name="commandLineString">String containing the command line arguments</param>
|
||||
/// <param name="windowsMode">Whether the / character initiates an argument</param>
|
||||
/// <returns>The parsed command line</returns>
|
||||
/// <remarks>
|
||||
/// You should always pass Environment.CommandLine to this methods to avoid
|
||||
/// some problems with the build-in command line tokenizer in .NET
|
||||
/// (which splits '--test"hello world"/v' into '--testhello world/v')
|
||||
/// </remarks>
|
||||
public static CommandLine Parse(string commandLineString, bool windowsMode) {
|
||||
return Parser.Parse(commandLineString, windowsMode);
|
||||
}
|
||||
|
||||
#region To Be Removed
|
||||
|
||||
/// <summary>Adds a loose value to the command line</summary>
|
||||
/// <param name="value">Value taht will be added</param>
|
||||
internal void addValue(StringSegment value) {
|
||||
/*
|
||||
Console.WriteLine("Discovered loose value: '" + value.ToString() + "'");
|
||||
*/
|
||||
|
||||
this.arguments.Add(
|
||||
Argument.ValueOnly(value, value.Offset, value.Count)
|
||||
return new CommandLine(
|
||||
Parser.Parse(commandLineString, windowsMode)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>Adds an argument to the command line</summary>
|
||||
/// <param name="argument">Argument that will be added</param>
|
||||
internal void addArgument(Argument argument) {
|
||||
/*
|
||||
Console.WriteLine("Discovered option: '" + argument.Raw.ToString() + "'");
|
||||
Console.WriteLine(" Name: '" + argument.Name + "'");
|
||||
if(argument.Value != null) {
|
||||
Console.WriteLine(" Value: '" + argument.Value + "'");
|
||||
}
|
||||
*/
|
||||
|
||||
this.arguments.Add(argument);
|
||||
/// <summary>Returns whether an argument with the specified name exists</summary>
|
||||
/// <param name="name">Name of the argument whose existence will be checked</param>
|
||||
/// <returns>True if an argument with the specified name exists</returns>
|
||||
public bool HasArgument(string name) {
|
||||
return (indexOfArgument(name) != -1);
|
||||
}
|
||||
|
||||
#if false
|
||||
/// <summary>Retrieves the value of the specified argument</summary>
|
||||
/// <param name="name">Name of the argument whose value will be retrieved</param>
|
||||
/// <returns>The value of the specified argument</returns>
|
||||
public string GetValue(string name) {
|
||||
int index = indexOfArgument(name);
|
||||
if(index == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
/// <summary>Retrieves the index of the argument with the specified name</summary>
|
||||
/// <param name="name">Name of the argument whose index will be returned</param>
|
||||
/// <returns>
|
||||
/// The index of the indicated argument of -1 if no argument with that name exists
|
||||
/// </returns>
|
||||
private int indexOfArgument(string name) {
|
||||
for(int index = 0; index < this.arguments.Count; ++index) {
|
||||
if(this.arguments[index].Name == name) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endregion // To Be Removed
|
||||
|
||||
/// <summary>Options that were specified on the command line</summary>
|
||||
public IList<Argument> Arguments {
|
||||
|
|
Loading…
Reference in New Issue
Block a user