Implement fully command line support

This commit is contained in:
fangrong 2024-08-01 18:26:28 +08:00
parent ed336a23b6
commit b5f1a84ce3
17 changed files with 13742 additions and 87 deletions

View File

@ -21,6 +21,58 @@ using System;
using System.Windows.Forms; using System.Windows.Forms;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using CommandLine;
using System.Collections.Generic;
using System.Linq;
[Verb("extract", HelpText = "Extract all files from nds rom.")]
internal class ExtractOptions
{
[Option('f', "file", Required = true, HelpText = "The path of nds rom file to be extract.")]
public string FilePath { get; set; }
[Option('o', "out", HelpText = "The output path. If not provided, will use the same path of rom file.")]
public string OutputPath { get; set; }
}
[Verb("replace", HelpText = "Replace all nitrofs files by dir.")]
internal class ReplaceOptions
{
[Option('f', "file", Required = true, HelpText = "The path of the input nds rom file.")]
public string FilePath { get; set; }
[Option('d', "dir", Required = true, HelpText = "The folder path which contains all nitrofs files. It should be named 'Root'.")]
public string ResPath { get; set; }
[Option('o', "out", Required = true, HelpText = "Set the output rom path.")]
public string OutputFile { get; set; }
[Option('t', "trim", HelpText = "Safe trim the output rom.")]
public bool SafeTrim { get; set; }
[Option('k', "keep-sig", HelpText = "Keep Original RSA SHA1 Signature for output rom.")]
public bool KeepSig { get; set; }
[Option('r', "re-comp", HelpText = "Recompress ARM9 binary for output rom.")]
public bool Recompress { get; set; }
[Option('b', "blz-cue", HelpText = "Use better compress method to compress ARM9 binary (BLZ-Cue). Will be ignore if -r/--re-comp not passed.")]
public bool BlzCue { get; set; }
}
[Verb("open", HelpText = "Open file(s) or a folder via TinkeDSi GUI")]
internal class OpenOptions
{
[Option('f', "folder", HelpText = "Call a folder select dialog then open the selected folder.")]
public bool IsFolder { get; set; }
[Value(0, MetaName = "RomPath", HelpText = "Path of the file(s). Can be provided multiple. Will be ignore if -f/--folder passed.")]
public IEnumerable<string> Props
{
get;
set;
}
}
namespace Tinke namespace Tinke
{ {
@ -32,6 +84,23 @@ namespace Tinke
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
public static extern bool FreeConsole(); public static extern bool FreeConsole();
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleOutputCP(uint wCodePageID);
public static string extractFilePath;
public static string extractOutputPath;
public static string replaceResPath;
public static string replaceInputFile;
public static string replaceOutputFile;
public static bool safeTrim = false;
public static bool keepSig = false;
public static bool recompressA9 = false;
public static bool blzcueA9 = false;
public static int curCommand = -1;
public static List<string> tblRoms;
public static bool bIsFolder = false;
public static bool bOpenDefault = false;
/// <summary> /// <summary>
/// Punto de entrada principal para la aplicación. /// Punto de entrada principal para la aplicación.
/// </summary> /// </summary>
@ -54,9 +123,93 @@ namespace Tinke
} }
#endregion #endregion
if (Environment.GetCommandLineArgs().Length >= 2)
{
if (Type.GetType("Mono.Runtime") == null)
{
Version osVersion = Environment.OSVersion.Version;
Version win7Version = new Version(6, 1);
AttachConsole(-1);
if (osVersion >= win7Version)
SetConsoleOutputCP(65001);
Console.WriteLine();
}
Parser.Default.ParseArguments<ExtractOptions, ReplaceOptions, OpenOptions>(args)
.WithParsed(HandleArgs)
.WithNotParsed(HandleErrors);
if (Type.GetType("Mono.Runtime") == null && curCommand == 0)
{
FreeConsole();
SendKeys.SendWait("{ENTER}");
}
}
if (curCommand == 0)
{
Application.Exit();
return;
}
Application.EnableVisualStyles(); Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false); Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Sistema()); Application.Run(new Sistema());
} }
private static void HandleArgs(object obj)
{
switch (obj)
{
case ExtractOptions e:
RunExtract(e);
break;
case ReplaceOptions p:
RunReplace(p);
break;
case OpenOptions o:
RunOpen(o);
break;
}
//process ExtractOptions
void RunExtract(ExtractOptions opts)
{
extractFilePath = opts.FilePath;
extractOutputPath = opts.OutputPath;
curCommand = 1;
}
//process ReplaceOptions
void RunReplace(ReplaceOptions opts)
{
replaceResPath = opts.ResPath;
replaceInputFile = opts.FilePath;
replaceOutputFile = opts.OutputFile;
safeTrim = opts.SafeTrim;
keepSig = opts.KeepSig;
recompressA9 = opts.Recompress;
blzcueA9 = opts.BlzCue;
curCommand = 2;
}
//process OpenOptions
void RunOpen(OpenOptions opts)
{
if (Environment.GetCommandLineArgs().Length <= 2)
{
bOpenDefault = true;
curCommand = -1;
return;
}
else
curCommand = 3;
tblRoms = opts.Props.ToList();
bIsFolder = opts.IsFolder;
}
}
private static void HandleErrors(IEnumerable<Error> obj)
{
curCommand = 0;
}
} }
} }

View File

@ -19,8 +19,6 @@
*/ */
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
//using System.ComponentModel;
//using System.Data;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -62,31 +60,17 @@ namespace Tinke
// The IE control of the Debug windows doesn't work in Mono // The IE control of the Debug windows doesn't work in Mono
isMono = (Type.GetType("Mono.Runtime") != null); isMono = (Type.GetType("Mono.Runtime") != null);
if (Environment.GetCommandLineArgs().Length == 2 && (Environment.GetCommandLineArgs()[1] == "-h" || Environment.GetCommandLineArgs()[1] == "--help")) if (Program.curCommand != -1 && Program.curCommand != 3)
{ {
Program.AttachConsole(-1); Console.WriteLine(this.Text);
Console.WriteLine("\n" + this.Text);
Console.WriteLine("Usage: Tinke.exe rom_name [option]");
Console.WriteLine("options:");
Console.WriteLine("-x: Extract all files from nds rom");
Console.WriteLine("-r: Replace all nitrofs files by dir, need -o to set an output rom path(-o Only allowed after -r)");
Console.WriteLine("-h or --help: Show this message, must be the first param...");
Program.FreeConsole();
SendKeys.SendWait("{ENTER}");
} }
sb = new StringBuilder(); sb = new StringBuilder();
TextWriter tw = new StringWriter(sb); TextWriter tw = new StringWriter(sb);
tw.NewLine = "<br>"; tw.NewLine = "<br>";
if (!isMono && !(Environment.GetCommandLineArgs().Length >= 3 && (Environment.GetCommandLineArgs()[2] == "-x" || Environment.GetCommandLineArgs()[2] == "-r"))) if (!isMono && (Program.curCommand == -1 || Program.curCommand == 3))
Console.SetOut(tw); Console.SetOut(tw);
if (Environment.GetCommandLineArgs().Length >= 3 && (Environment.GetCommandLineArgs()[2] == "-x" || Environment.GetCommandLineArgs()[2] == "-r"))
{
Program.AttachConsole(-1);
Console.WriteLine("\n" + this.Text);
}
#region Language #region Language
if (!File.Exists(Application.StartupPath + Path.DirectorySeparatorChar + "Tinke.xml")) if (!File.Exists(Application.StartupPath + Path.DirectorySeparatorChar + "Tinke.xml"))
{ {
@ -106,13 +90,6 @@ namespace Tinke
if (!langFile.EndsWith(".xml")) if (!langFile.EndsWith(".xml"))
continue; ; continue; ;
//string flag = Application.StartupPath + Path.DirectorySeparatorChar + "langs" + Path.DirectorySeparatorChar + langFile.Substring(langFile.Length - 9, 5) + ".png";
//Image iFlag;
//if (File.Exists(flag))
//iFlag = Image.FromFile(flag);
//else
//iFlag = iconos.Images[1];
XElement xLang = XElement.Load(langFile); XElement xLang = XElement.Load(langFile);
if (xLang.Name != "Language") if (xLang.Name != "Language")
continue; continue;
@ -135,8 +112,13 @@ namespace Tinke
void Sistema_Load(object sender, EventArgs e) void Sistema_Load(object sender, EventArgs e)
{ {
string[] filesToRead = new string[1]; string[] filesToRead = new string[1];
if (Environment.GetCommandLineArgs().Length == 1) if (Program.curCommand == -1)
{ {
if (!isMono && Program.bOpenDefault)
{
Program.FreeConsole();
SendKeys.SendWait("{ENTER}");
}
OpenFileDialog o = new OpenFileDialog(); OpenFileDialog o = new OpenFileDialog();
o.CheckFileExists = true; o.CheckFileExists = true;
o.Multiselect = true; o.Multiselect = true;
@ -149,9 +131,14 @@ namespace Tinke
filesToRead = o.FileNames; filesToRead = o.FileNames;
o.Dispose(); o.Dispose();
} }
else if (Environment.GetCommandLineArgs().Length == 2) else if (Program.curCommand == 3)
{ {
if (Environment.GetCommandLineArgs()[1] == "-fld") if (!isMono)
{
Program.FreeConsole();
SendKeys.SendWait("{ENTER}");
}
if (Program.bIsFolder)
{ {
FolderBrowserDialog o = new FolderBrowserDialog(); FolderBrowserDialog o = new FolderBrowserDialog();
o.ShowNewFolderButton = false; o.ShowNewFolderButton = false;
@ -163,49 +150,58 @@ namespace Tinke
filesToRead[0] = o.SelectedPath; filesToRead[0] = o.SelectedPath;
o.Dispose(); o.Dispose();
} }
else if (Environment.GetCommandLineArgs()[1] == "-h" || Environment.GetCommandLineArgs()[1] == "--help") else if (Program.tblRoms.Count() == 1)
{ {
Application.Exit(); filesToRead[0] = Program.tblRoms[0];
return;
} }
else else
filesToRead[0] = Environment.GetCommandLineArgs()[1]; {
filesToRead = new String[Program.tblRoms.Count()];
Array.Copy(Program.tblRoms.ToArray(), 0, filesToRead, 0, filesToRead.Length);
} }
else if (Environment.GetCommandLineArgs().Length >= 3) }
else if (Program.curCommand == 1)
{ {
if (Environment.GetCommandLineArgs()[2] == "-x") filesToRead[0] = Program.extractFilePath;
{
filesToRead[0] = Environment.GetCommandLineArgs()[1];
ReadGame(filesToRead[0]); ReadGame(filesToRead[0]);
sFolder folderSelect = accion.Root; sFolder folderSelect = accion.Root;
if (Environment.GetCommandLineArgs().Length > 3 && Environment.GetCommandLineArgs()[3] is string) if (Program.extractOutputPath is string)
{ {
Directory.CreateDirectory(Environment.GetCommandLineArgs()[3] + Path.DirectorySeparatorChar + folderSelect.name); Directory.CreateDirectory(Program.extractOutputPath + Path.DirectorySeparatorChar + folderSelect.name);
RecursivoExtractFolder(folderSelect, Environment.GetCommandLineArgs()[3] + Path.DirectorySeparatorChar + folderSelect.name); RecursivoExtractFolder(folderSelect, Program.extractOutputPath + Path.DirectorySeparatorChar + folderSelect.name);
Console.WriteLine("Extract all files to " + Environment.GetCommandLineArgs()[3] + Path.DirectorySeparatorChar + folderSelect.name); Console.WriteLine("Extract all files to " + Program.extractOutputPath + Path.DirectorySeparatorChar + folderSelect.name);
} else }
else
Console.WriteLine("Param error..."); Console.WriteLine("Param error...");
if (!isMono)
{
Program.FreeConsole(); Program.FreeConsole();
SendKeys.SendWait("{ENTER}"); SendKeys.SendWait("{ENTER}");
}
this.Close();
Application.Exit(); Application.Exit();
} else if (Environment.GetCommandLineArgs()[2] == "-r" && Environment.GetCommandLineArgs().Length > 5 && Environment.GetCommandLineArgs()[4] == "-o")
{
filesToRead[0] = Environment.GetCommandLineArgs()[1];
ReadGame(filesToRead[0]);
if (Environment.GetCommandLineArgs()[3] is string)
{
ChangeByDir(Environment.GetCommandLineArgs()[3]);
}
// parse saving args
for(int i = 5; i < Environment.GetCommandLineArgs().Length; i++)
{
}
return; return;
} }
filesToRead = new String[Environment.GetCommandLineArgs().Length - 1]; else if (Program.curCommand == 2)
Array.Copy(Environment.GetCommandLineArgs(), 1, filesToRead, 0, filesToRead.Length); {
filesToRead[0] = Program.replaceInputFile;
ReadGame(filesToRead[0]);
if (Program.replaceResPath is string)
{
ChangeByDir(Program.replaceResPath);
} else
Console.WriteLine("Param error...");
btnSaveROM_Click(null, null);
if (!isMono)
{
Program.FreeConsole();
SendKeys.SendWait("{ENTER}");
}
this.Close();
Application.Exit();
return;
} }
Thread loadrom = new Thread(ThreadEspera) Thread loadrom = new Thread(ThreadEspera)
@ -254,7 +250,6 @@ namespace Tinke
xml.Element("WindowDebug").Value = toolStripDebug.Checked.ToString(); xml.Element("WindowDebug").Value = toolStripDebug.Checked.ToString();
xml.Element("WindowInformation").Value = toolStripInfoRom.Checked.ToString(); xml.Element("WindowInformation").Value = toolStripInfoRom.Checked.ToString();
xml.Element("InstantSearch").Value = checkSearch.Checked.ToString(); xml.Element("InstantSearch").Value = checkSearch.Checked.ToString();
//xml.Element("ModeWindow").Value = toolStripVentana.Checked.ToString();
xml = xml.Parent; xml = xml.Parent;
xml.Save(Application.StartupPath + Path.DirectorySeparatorChar + "Tinke.xml"); xml.Save(Application.StartupPath + Path.DirectorySeparatorChar + "Tinke.xml");
@ -1504,6 +1499,16 @@ namespace Tinke
bool bIsFlashCartFW = false; bool bIsFlashCartFW = false;
Nitro.Estructuras.ROMHeader header = romInfo.Cabecera; Nitro.Estructuras.ROMHeader header = romInfo.Cabecera;
if (Program.curCommand == 2)
{
keep_original = Program.keepSig;
if (Program.safeTrim)
header.trimmedRom = true;
a9_recomp = Program.recompressA9;
a9_bestcomp = Program.blzcueA9;
}
else
{
Dialog.SaveOptions dialog = new Dialog.SaveOptions(); Dialog.SaveOptions dialog = new Dialog.SaveOptions();
if (dialog.ShowDialog() != System.Windows.Forms.DialogResult.OK) if (dialog.ShowDialog() != System.Windows.Forms.DialogResult.OK)
return; return;
@ -1517,12 +1522,13 @@ namespace Tinke
a9_bestcomp = true; a9_bestcomp = true;
if (dialog.IsFlashCartFirmware) if (dialog.IsFlashCartFirmware)
bIsFlashCartFW = true; bIsFlashCartFW = true;
}
Thread create = new Thread(ThreadEspera) Thread create = new Thread(ThreadEspera)
{ {
IsBackground = true IsBackground = true
}; };
if (!isMono) if (!isMono && Program.curCommand != 2)
create.Start("S05"); create.Start("S05");
// Get special files // Get special files
@ -1926,22 +1932,27 @@ namespace Tinke
Console.Write("<br>"); Console.Write("<br>");
#endregion #endregion
if (!isMono) if (!isMono && Program.curCommand != 2)
CloseEspera(create); CloseEspera(create);
// Obtenemos el nuevo archivo para guardar // Obtenemos el nuevo archivo para guardar
SaveFileDialog o = new SaveFileDialog(); SaveFileDialog o = new SaveFileDialog();
if (Program.curCommand == 2)
o.FileName = Program.replaceOutputFile;
else
{
o.AddExtension = true; o.AddExtension = true;
o.DefaultExt = ".nds"; o.DefaultExt = ".nds";
o.Filter = "Nintendo DS ROM (*.nds)|*.nds"; o.Filter = "Nintendo DS ROM (*.nds)|*.nds";
o.OverwritePrompt = true; o.OverwritePrompt = true;
if (o.ShowDialog() == System.Windows.Forms.DialogResult.OK) }
if (Program.curCommand == 2 || o.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{ {
Thread saverom = new Thread(ThreadEspera) Thread saverom = new Thread(ThreadEspera)
{ {
IsBackground = true IsBackground = true
}; };
if (!isMono) if (!isMono && Program.curCommand != 2)
saverom.Start("S06"); saverom.Start("S06");
Console.WriteLine(Tools.Helper.GetTranslation("Messages", "S0D"), o.FileName); Console.WriteLine(Tools.Helper.GetTranslation("Messages", "S0D"), o.FileName);
@ -1977,7 +1988,7 @@ namespace Tinke
Console.WriteLine("<b>" + Tools.Helper.GetTranslation("Messages", "S09") + "</b>", new FileInfo(o.FileName).Length); Console.WriteLine("<b>" + Tools.Helper.GetTranslation("Messages", "S09") + "</b>", new FileInfo(o.FileName).Length);
accion.IsNewRom = false; accion.IsNewRom = false;
if (!isMono) if (!isMono && Program.curCommand != 2)
{ {
CloseEspera(saverom); CloseEspera(saverom);
debug.Add_Text(sb.ToString()); debug.Add_Text(sb.ToString());

View File

@ -145,6 +145,9 @@
<BaseAddress>4194304</BaseAddress> <BaseAddress>4194304</BaseAddress>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="CommandLine, Version=2.9.1.0, Culture=neutral, PublicKeyToken=5a870481e358d379, processorArchitecture=MSIL">
<HintPath>..\packages\CommandLineParser.2.9.1\lib\net461\CommandLine.dll</HintPath>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
@ -316,6 +319,7 @@
<DependentUpon>VisorHex.cs</DependentUpon> <DependentUpon>VisorHex.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
<None Include="app.config" /> <None Include="app.config" />
<None Include="packages.config" />
<None Include="Properties\Settings.settings"> <None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator> <Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput> <LastGenOutput>Settings.Designer.cs</LastGenOutput>

4
Tinke/packages.config Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="CommandLineParser" version="2.9.1" targetFramework="net48" />
</packages>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2005 - 2015 Giacomo Stelluti Scala & Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,351 @@
[![Build status](https://ci.appveyor.com/api/projects/status/p61dj8udxs2aocmo/branch/master?svg=true)](https://ci.appveyor.com/project/commandlineparser/commandline/branch/master)
[![NuGet](https://img.shields.io/nuget/dt/commandlineparser.svg)](http://nuget.org/packages/commandlineparser)
[![NuGet](https://img.shields.io/nuget/v/commandlineparser.svg)](https://www.nuget.org/packages/CommandLineParser/)
[![NuGet](https://img.shields.io/nuget/vpre/commandlineparser.svg)](https://www.nuget.org/packages/CommandLineParser/)
[![Join the Gitter chat!](https://badges.gitter.im/gsscoder/commandline.svg)](https://gitter.im/gsscoder/commandline?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
# Command Line Parser Library for CLR and NetStandard
**Note:** the API surface has changed since v1.9.x and earlier. If you are looking for documentation on v1.9.x, please see [stable-1.9.71.2](https://github.com/gsscoder/commandline/tree/stable-1.9.71.2)
The Command Line Parser Library offers CLR applications a clean and concise API for manipulating command line arguments and related tasks, such as defining switches, options and verb commands. It allows you to display a help screen with a high degree of customization and a simple way to report syntax errors to the end user.
```
C:\Project> NuGet Install CommandLineParser
```
# Nightly Build
Nightly version of the CommandLineParser can be downloaded from github [Releases](https://github.com/commandlineparser/commandline/releases).
The Last new features and fixes, read [changelog](https://github.com/commandlineparser/commandline/blob/master/CHANGELOG.md)
_NOTE: Mentioned F# Support is provided via ```CommandLineParser.FSharp``` package with FSharp dependencies._
__This library provides _hassle free_ command line parsing with a constantly updated API since 2005.__
# At a glance:
- Compatible with __.NET Framework 4.0+__, __Mono 2.1+ Profile__, __.NET Standard__ and __.NET Core__
- Doesn't depend on other packages (No dependencies beyond standard base libraries)
- One line parsing using default singleton: `CommandLine.Parser.Default.ParseArguments(...)` and three overload methods.
- Automatic or one line help screen generator: `HelpText.AutoBuild(...)`.
- Supports `--help`, `--version`, `version` and `help [verb]` by default with customization.
- Map to sequences (via `IEnumerable<T>` and similar) and scalar types, including Enums and `Nullable<T>`.
- You can also map to every type with a constructor that accepts a string (like `System.Uri`) for reference and value types.
- Verbs can be array of types collected from Plugins or IoC container.
- Define [verb commands](https://github.com/commandlineparser/commandline/wiki/Verbs) similar to `git commit -a`.
- Support default verb.
- Support Mutable and Immutable types.
- Support HelpText localization.
- Support ordering of options in HelpText.
- Support [Mutually Exclusive Options](https://github.com/commandlineparser/commandline/wiki/Mutually-Exclusive-Options) and [Option groups](https://github.com/commandlineparser/commandline/wiki/Option-Groups).
- Support named and value options.
- Support Asynchronous programming with async and await.
- Unparsing support: `CommandLine.Parser.Default.FormatCommandLine<T>(T options)`.
- CommandLineParser.FSharp package is F#-friendly with support for `option<'a>`, see [demo](https://github.com/commandlineparser/commandline/blob/master/demo/fsharp-demo.fsx). _NOTE: This is a separate NuGet package._
- Include wiki documentation with lot of examples ready to run online.
- Support Source Link and symbolic nuget package snupkg.
- Tested in Windows, Linux Ubuntu 18.04 and Mac OS.
- Most of features applies with a [CoC](http://en.wikipedia.org/wiki/Convention_over_configuration) philosophy.
- C# demo: source [here](https://github.com/commandlineparser/commandline/tree/master/demo/ReadText.Demo).
# Getting Started with the Command Line Parser Library
You can utilize the parser library in several ways:
- Install via NuGet/Paket: [https://www.nuget.org/packages/CommandLineParser/](https://www.nuget.org/packages/CommandLineParser/)
- Integrate directly into your project by copying the .cs files into your project.
- ILMerge during your build process.
## Quick Start Examples
1. Create a class to define valid options, and to receive the parsed options.
2. Call ParseArguments with the args string array.
C# Quick Start:
```cs
using System;
using CommandLine;
namespace QuickStart
{
class Program
{
public class Options
{
[Option('v', "verbose", Required = false, HelpText = "Set output to verbose messages.")]
public bool Verbose { get; set; }
}
static void Main(string[] args)
{
Parser.Default.ParseArguments<Options>(args)
.WithParsed<Options>(o =>
{
if (o.Verbose)
{
Console.WriteLine($"Verbose output enabled. Current Arguments: -v {o.Verbose}");
Console.WriteLine("Quick Start Example! App is in Verbose mode!");
}
else
{
Console.WriteLine($"Current Arguments: -v {o.Verbose}");
Console.WriteLine("Quick Start Example!");
}
});
}
}
}
```
## C# Examples:
<details>
<summary>Click to expand!</summary>
```cs
class Options
{
[Option('r', "read", Required = true, HelpText = "Input files to be processed.")]
public IEnumerable<string> InputFiles { get; set; }
// Omitting long name, defaults to name of property, ie "--verbose"
[Option(
Default = false,
HelpText = "Prints all messages to standard output.")]
public bool Verbose { get; set; }
[Option("stdin",
Default = false,
HelpText = "Read from stdin")]
public bool stdin { get; set; }
[Value(0, MetaName = "offset", HelpText = "File offset.")]
public long? Offset { get; set; }
}
static void Main(string[] args)
{
CommandLine.Parser.Default.ParseArguments<Options>(args)
.WithParsed(RunOptions)
.WithNotParsed(HandleParseError);
}
static void RunOptions(Options opts)
{
//handle options
}
static void HandleParseError(IEnumerable<Error> errs)
{
//handle errors
}
```
</details>
Demo to show IEnumerable options and other usage: [Online Demo](https://dotnetfiddle.net/wrcAxr)
## F# Examples:
<details>
<summary>Click to expand!</summary>
```fsharp
type options = {
[<Option('r', "read", Required = true, HelpText = "Input files.")>] files : seq<string>;
[<Option(HelpText = "Prints all messages to standard output.")>] verbose : bool;
[<Option(Default = "русский", HelpText = "Content language.")>] language : string;
[<Value(0, MetaName="offset", HelpText = "File offset.")>] offset : int64 option;
}
let main argv =
let result = CommandLine.Parser.Default.ParseArguments<options>(argv)
match result with
| :? Parsed<options> as parsed -> run parsed.Value
| :? NotParsed<options> as notParsed -> fail notParsed.Errors
```
</details>
## VB.NET Example:
<details>
<summary>Click to expand!</summary>
```vb
Class Options
<CommandLine.Option('r', "read", Required := true,
HelpText:="Input files to be processed.")>
Public Property InputFiles As IEnumerable(Of String)
' Omitting long name, defaults to name of property, ie "--verbose"
<CommandLine.Option(
HelpText:="Prints all messages to standard output.")>
Public Property Verbose As Boolean
<CommandLine.Option(Default:="中文",
HelpText:="Content language.")>
Public Property Language As String
<CommandLine.Value(0, MetaName:="offset",
HelpText:="File offset.")>
Public Property Offset As Long?
End Class
Sub Main(ByVal args As String())
CommandLine.Parser.Default.ParseArguments(Of Options)(args) _
.WithParsed(Function(opts As Options) RunOptionsAndReturnExitCode(opts)) _
.WithNotParsed(Function(errs As IEnumerable(Of [Error])) 1)
End Sub
```
</details>
## For verbs:
1. Create separate option classes for each verb. An options base class is supported.
2. Call ParseArguments with all the verb attribute decorated options classes.
3. Use MapResult to direct program flow to the verb that was parsed.
### C# example:
<details>
<summary>Click to expand!</summary>
```csharp
[Verb("add", HelpText = "Add file contents to the index.")]
class AddOptions {
//normal options here
}
[Verb("commit", HelpText = "Record changes to the repository.")]
class CommitOptions {
//commit options here
}
[Verb("clone", HelpText = "Clone a repository into a new directory.")]
class CloneOptions {
//clone options here
}
int Main(string[] args) {
return CommandLine.Parser.Default.ParseArguments<AddOptions, CommitOptions, CloneOptions>(args)
.MapResult(
(AddOptions opts) => RunAddAndReturnExitCode(opts),
(CommitOptions opts) => RunCommitAndReturnExitCode(opts),
(CloneOptions opts) => RunCloneAndReturnExitCode(opts),
errs => 1);
}
```
</details>
### VB.NET example:
<details>
<summary>Click to expand!</summary>
```vb
<CommandLine.Verb("add", HelpText:="Add file contents to the index.")>
Public Class AddOptions
'Normal options here
End Class
<CommandLine.Verb("commit", HelpText:="Record changes to the repository.")>
Public Class CommitOptions
'Normal options here
End Class
<CommandLine.Verb("clone", HelpText:="Clone a repository into a new directory.")>
Public Class CloneOptions
'Normal options here
End Class
Function Main(ByVal args As String()) As Integer
Return CommandLine.Parser.Default.ParseArguments(Of AddOptions, CommitOptions, CloneOptions)(args) _
.MapResult(
(Function(opts As AddOptions) RunAddAndReturnExitCode(opts)),
(Function(opts As CommitOptions) RunCommitAndReturnExitCode(opts)),
(Function(opts As CloneOptions) RunCloneAndReturnExitCode(opts)),
(Function(errs As IEnumerable(Of [Error])) 1)
)
End Function
```
</details>
### F# Example:
<details>
<summary>Click to expand!</summary>
```fs
open CommandLine
[<Verb("add", HelpText = "Add file contents to the index.")>]
type AddOptions = {
// normal options here
}
[<Verb("commit", HelpText = "Record changes to the repository.")>]
type CommitOptions = {
// normal options here
}
[<Verb("clone", HelpText = "Clone a repository into a new directory.")>]
type CloneOptions = {
// normal options here
}
[<EntryPoint>]
let main args =
let result = Parser.Default.ParseArguments<AddOptions, CommitOptions, CloneOptions> args
match result with
| :? CommandLine.Parsed<obj> as command ->
match command.Value with
| :? AddOptions as opts -> RunAddAndReturnExitCode opts
| :? CommitOptions as opts -> RunCommitAndReturnExitCode opts
| :? CloneOptions as opts -> RunCloneAndReturnExitCode opts
| :? CommandLine.NotParsed<obj> -> 1
```
</details>
# Release History
See the [changelog](CHANGELOG.md)
# Contributors
First off, _Thank you!_ All contributions are welcome.
Please consider sticking with the GNU getopt standard for command line parsing.
Additionally, for easiest diff compares, please follow the project's tabs settings. Utilizing the EditorConfig extension for Visual Studio/your favorite IDE is recommended.
__And most importantly, please target the ```develop``` branch in your pull requests!__
## Main Contributors (alphabetical order):
- Alexander Fast (@mizipzor)
- Dan Nemec (@nemec)
- Eric Newton (@ericnewton76)
- Kevin Moore (@gimmemoore)
- Moh-Hassan (@moh-hassan)
- Steven Evans
- Thomas Démoulins (@Thilas)
## Resources for newcomers:
- [Wiki](https://github.com/commandlineparser/commandline/wiki)
- [GNU getopt](http://www.gnu.org/software/libc/manual/html_node/Getopt.html)
# Contacts:
- Giacomo Stelluti Scala
- gsscoder AT gmail DOT com (_use this for everything that is not available via GitHub features_)
- GitHub: [gsscoder](https://github.com/gsscoder)
- [Blog](http://gsscoder.blogspot.it)
- [Twitter](http://twitter.com/gsscoder)
- Dan Nemec
- Eric Newton
- ericnewton76+commandlineparser AT gmail DOT com
- GitHub: [ericnewton76](https://github.com/ericnewton76)
- Blog:
- Twitter: [enorl76](http://twitter.com/enorl76)
- Moh-Hassan

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff