Unable to parse simple command line with commandlineparser - c#

I have to parse an imposed command line which mix single/double dash args, args with = or as separator,etc (not very proper....)
The command line is like myexe.exe -Url=https://blabla.com/ --TestValue=val1 -monoapp -Ctx "default ctx" Open -Test2=CO0ZJP6f-ca
I'm trying to do that with commandlineparser.
(I suppose it's able to manage that, right ? )
So first I'm trying to parse the first parameter (myexe.exe -Url=https://blabla.com/).
public class CommandLineOptions
{
[Option("Url", Required = true)]
public string Url { get; set; }
}
....... In another file but in the same assembly
static void Main(string[] args) // args[0] = "-Url=https://blabla.com/"
{
var commandLineOptions = new CommandLineOptions();
var parseResult = Parser.Default.ParseArguments<CommandLineOptions>(args).WithParsed(result => commandLineOptions = result);
System.Console.WriteLine(parseResult.Tag); //NotParsed
System.Console.WriteLine(commandLineOptions.Url);
}
With that code, I have 2 errors CommandLine.MissingRequiredOptionError and CommandLine.UnknownOptionError.
(The MissingRequiredOptionError is produced beacause it cannot find the Url parameter)
So do you know where is my mistake ?
Thanks in advance for your help ;)

So final dev from commandlineparser said it isn't possible to parse it.
A single line option must be one char option.
The only way to bypass that is to preprocess the arguments.
I did this, it's working but it not allow short option composition (like in tar -xvf for example)
args = args.Select(arg => Regex.IsMatch(arg, "^-\\w{2,}") ? "-" + arg : arg ).ToArray();

Related

Parsing a string using command Line parser

I downloaded this package https://github.com/commandlineparser/commandline
and I wanted to perform parsing for strings like
string str = "file:xxxx\\xxxx\\xxxxx.sh val:-a nsdd m";
so
file = xxxx\\xxxx\\xxxxx.sh
val = -a nsdd m
I wanted to know if anyone had a library in mind or has used the specified library to obtain the parameters specified in the string.
I am having a hard time understanding the example on how to parse that string and obtain the file parameter and val parameter. I know i could do string manipulation but I rather use an existing tested durable solution for this.
I've used this library and it's a solid choice.
Here's a very basic sample using some of what you posted, see code comments for clarification.
class Program
{
static void Main(string[] args)
{
// args a space separated array so you should use an array for your test
// args are identified with the `-` so you should set args like `-f somefilenamehere`
// args specified are -f and -v
string[] arguments = new[] {"-f file:xxxx\\xxxx\\xxxxx.sh", "-v nsdd" };
string file = string.Empty;
string value = string.Empty;
// you would pull your args off the options, if they are successfully parsed
// and map them to your applications properties/settings
Parser.Default.ParseArguments<Options>(arguments)
.WithParsed<Options>(o =>
{
file = o.InputFile; // map InputFile arg to file property
value = o.Value; // map Value arg to value property
});
Console.WriteLine($"file = {file}");
Console.WriteLine($"value = {value}");
Console.ReadLine();
// output:
// file = file:xxxx\xxxx\xxxxx.sh
// value = nsdd
}
}
// the options class is used to define your arg tokens and map them to the Options property
class Options
{
[Option('f', "file", Required = true, HelpText = "Input files to be processed.")]
public string InputFile { get; set; }
[Option('v', "value", Required = true, HelpText = "Value to be used")]
public string Value { get; set; }
}

Passing Quotation Mark Character (") as C# Console Application Argument

I have a project to demonstrate a program similar to the "echo" command in the MS-DOS Command Line. Here is the code in C#:
using System;
namespace arguments
{
class Program
{
static void Main(string[] args)
{
try
{
switch (args[0])
{
case "/?":
string location = System.Reflection.Assembly.GetEntryAssembly().Location;
string name = System.IO.Path.GetFileName(location);
Console.WriteLine("Displays messages\nSyntax: {0} [message]", name);
Environment.Exit(0);
break;
}
if (args.Length >= 0)
{
string x = "";
foreach (var item in args)
{
x += item.ToString() + " ";
}
Console.WriteLine(Convert.ToString(x)); // this should eliminate vulnerabilities.
}
}
catch
{
string location = System.Reflection.Assembly.GetEntryAssembly().Location;
string name = System.IO.Path.GetFileName(location);
Console.WriteLine("Displays messages\nSyntax: {0} [message]", name);
}
}
}
}
This does a pretty efficient job at doing what it's supposed to do. Then I got into trying to exploit it in any way I could.
In command prompt, I ran arguments.exe ", this is supposed to print out ". But that's not really what happened. I then tried the same with the echo command by running echo ", and it, like it's supposed to, printed out ". This is mind boggling because I wouldn't have even thought this would be a problem. I couldn't get it to pose a great threat, just confused me for a minute.
My question is, is there any way to pass the quotation mark (") as argument to this console application?
Here is a picture to demonstrate it a little bit better: http://prntscr.com/cm9yal
void Main(string[] args)
args array here contains the arguments which have been passed to your application. Because arguments may have spaces they can be surrounded by quotes.
For this reason you won't get the string you have placed as argument. You will also loose any number of spaces between quoted parameters.
If you need the raw command line string, use:
string cmdline = System.Environment.CommandLine;
To be able to get the single quote, you'll need to bypass the default parsing performed by the CLR when populating the args array. You can do this by examining Environment.CommandLine, which in the case you describe above will return something along the lines of:
ConsoleApplication1.exe \"
Note, the argument I passed was simply " (not the escaped variant shown).

c# get value from registry without parameters

I am trying to get the path to AcroRd32.exe by invoking the following code:
public static string acrobatPath = Registry.GetValue(#"HKEY_CLASSES_ROOT\Applications\AcroRD32.exe\shell\Read\command", "", 0).ToString();
What I receive is the right value:
"C:\Program Files\Adobe\Reader 9.0\Reader\AcroRd32.exe" "%1"
but I want only the path to AcroRd32.exe without "%1".
I could now use the split command:
public static string acrobatPath = Registry.GetValue(#"HKEY_CLASSES_ROOT\Applications\AcroRD32.exe\shell\Read\command", "", 0).ToString();
string[] split = new string[2];
split = acrobatPath.Split('"');
// mask path with ""
acrobatPath = "\"" + split[1] + "\""; //get only path
but the value acrobatPath cannot be changed because of static attribute.
I also cannot use substr() because path can differ e.g. if there is no parameter at the end ("%1").
How can I extract the path and set the static variable in one go?
Use static constructor for your class, and do all the work for string manipulation there.
class YourClass
{
public static string acrobatPath;
// This static constructor will be called before first access to your type.
static YourClass()
{
acrobatPath = Registry.GetValue(#"HKEY_CLASSES_ROOT\Applications\AcroRD32.exe\shell\Read\command", "", 0).ToString();
string[] split = new string[2];
split = acrobatPath.Split('"');
// mask path with ""
acrobatPath = "\"" + split[1] + "\""; //get only path
}
}
but the value acrobatPath cannot be changed because of static attribute.
This statement makes no sense. You can change a static variable. The way your using the static string to be set the to the value of the register key ( which isn't going to change if it does exist ) is the reason you cannot change it.
The solution would be to change how the code works to be a method.
As you have already accepted Vladimir Perevalov's answer I won't go into a great amount of detail. What I would do is the following:
1) Get the installation directory of Adobe Reader by reading the installation directory. I would set this to a variable which I was able to modify at will.
2) I would modify the string only to get the path
3) I would set the current value of this string I just create to the static variable.
This does exactly what Vladimir Perevalov's code does, it simply uses a function, instead of a class. Of course the method would be static and in the same class as the static variable. Of course there is nothing wrong with using a STATIC constructor, I always have considered a constructor to be a specialized method, I just wanted to point out you CAN modify a static variable.

extract query string from a URL string

I am reading from history, and I want that when i come across a google query, I can extract the query string. I am not using request or httputility since i am simply parsing a string. however, when i come across URLs like this, my program fails to parse it properly:
http://www.google.com.mt/search?client=firefox-a&rls=org.mozilla%3Aen-US%3Aofficial&channel=s&hl=mt&source=hp&biw=986&bih=663&q=hotmail&meta=&btnG=Fittex+bil-Google
what i was trying to do is get the index of q= and the index of & and take the words in between but in this case the index of & will be smaller than q= and it will give me errors.
any suggestions?
thanks for your answers, all seem good :) p.s. i couldn't use httputility, not I don't want to. when i add a reference to system.web, httputility isn't included! it's only included in an asp.net application. Thanks again
It's not clear why you don't want to use HttpUtility. You could always add a reference to System.Web and use it:
var parsedQuery = HttpUtility.ParseQueryString(input);
Console.WriteLine(parsedQuery["q"]);
If that's not an option then perhaps this approach will help:
var query = input.Split('&')
.Single(s => s.StartsWith("q="))
.Substring(2);
Console.WriteLine(query);
It splits on & and looks for the single split result that begins with "q=" and takes the substring at position 2 to return everything after the = sign. The assumption is that there will be a single match, which seems reasonable for this case, otherwise an exception will be thrown. If that's not the case then replace Single with Where, loop over the results and perform the same substring operation in the loop.
EDIT: to cover the scenario mentioned in the comments this updated version can be used:
int index = input.IndexOf('?');
var query = input.Substring(index + 1)
.Split('&')
.SingleOrDefault(s => s.StartsWith("q="));
if (query != null)
Console.WriteLine(query.Substring(2));
If you don't want to use System.Web.HttpUtility (thus be able to use the client profile), you can still use Mono HttpUtility.cs which is only an independent .cs file that you can embed in your application. Then you can simply use the ParseQueryString method inside the class to parse the query string properly.
here is the solution -
string GetQueryString(string url, string key)
{
string query_string = string.Empty;
var uri = new Uri(url);
var newQueryString = HttpUtility.ParseQueryString(uri.Query);
query_string = newQueryString[key].ToString();
return query_string;
}
Why don't you create a code which returns the string from the q= onwards till the next &?
For example:
string s = historyString.Substring(url.IndexOf("q="));
int newIndex = s.IndexOf("&");
string newString = s.Substring(0, newIndex);
Cheers
Use the tools available:
String UrlStr = "http://www.google.com.mt/search?client=firefox-a&rls=org.mozilla%3Aen-US%3Aofficial&channel=s&hl=mt&source=hp&biw=986&bih=663&q=hotmail&meta=&btnG=Fittex+bil-Google";
NameValueCollection Items = HttpUtility.ParseQueryString(UrlStr);
String QValue = Items["q"];
If you really need to do the parsing yourself, and are only interested in the value for 'q' then the following would work:
string url = #"http://www.google.com.mt/search?" +
"client=firefoxa&rls=org.mozilla%3Aen-" +
"US%3Aofficial&channel=s&hl=mt&source=hp&" +
"biw=986&bih=663&q=hotmail&meta=&btnG=Fittex+bil-Google";
int question = url.IndexOf("?");
if(question>-1)
{
int qindex = url.IndexOf("q=", question);
if (qindex > -1)
{
int ampersand = url.IndexOf('&', qindex);
string token = null;
if (ampersand > -1)
token = url.Substring(qindex+2, ampersand - qindex - 2);
else
token = url.Substring(qindex+2);
Console.WriteLine(token);
}
}
But do try to look at using a proper URL parser, it will save you a lot of hassle in the future.
(amended this question to include a check for the '?' token, and support 'q' values at the end of the query string (without the '&' at the end) )
And that's why you should use Uri and HttpUtility.ParseQueryString.
HttpUtility is fine for the .Net Framework. However that class is not available for WinRT apps. If you want to get the parameters from a url in a Windows Store App you need to use WwwFromUrlDecoder. You create an object from this class with the query string you want to get the parameters from, the object has an enumerator and supports also lambda expressions.
Here's an example
var stringUrl = "http://localhost/?name=Jonathan&lastName=Morales";
var decoder = new WwwFormUrlDecoder(stringUrl);
//Using GetFirstByName method
string nameValue = decoder.GetFirstByName("name");
//nameValue has "Jonathan"
//Using Lambda Expressions
var parameter = decoder.FirstOrDefault(p => p.Name.Contains("last")); //IWwwFormUrlDecoderEntry variable type
string parameterName = parameter.Name; //lastName
string parameterValue = parameter.Value; //Morales
You can also see http://www.dzhang.com/blog/2012/08/21/parsing-uri-query-strings-in-windows-8-metro-style-apps

how to parse main arguments?

How can I find this information :
think we started this process :
testFile.exe i- 100 k- "hello" j-"C:\" "D:\Images" f- "true"
Now how can I get main argument when application started so I have :
int i = ... ; //i will be 100
string k = ... ; // k = hello
string[] path = ... ; // = path[0] = "C:\" , path[1] = "D:\Images"
bool f = ... ; // f = true;
regards
The arguments are passed to the Main function that is being called:
static void Main(string[] args)
{
// The args array contain all the arguments being passed:
// args[0] = "i-"
// args[1] = "100"
// args[2] = "k-"
// args[3] = "hello"
// ...
}
Arguments are in the same order as passed in the command line. If you want to use named arguments you may take a look at this post which suggests NDesk.Options and Mono.Options.
You can use Environment.CommandLine or Environment.GetCommandLineArgs()
String[] arguments = Environment.GetCommandLineArgs();
More info on MSDN
As already answered, you can use the string[] args parameter or Environment.GetCommandLineArgs(). Note that for CLickOnce deployed apps you need something else.
You can do your own processing on the string[] or use a library, like this one on CodePlex.
For some tricky details on spaces in filenames and escaping quotes, see this SO question.
You could use NDesk.Options. Here is their documentation.

Categories