Skip to content

Instantly share code, notes, and snippets.

@TheFlash2k
Last active August 27, 2022 17:53
Show Gist options
  • Save TheFlash2k/1f8f94b3f8cb5f1c8e090ef5feb90963 to your computer and use it in GitHub Desktop.
Save TheFlash2k/1f8f94b3f8cb5f1c8e090ef5feb90963 to your computer and use it in GitHub Desktop.
A Basic C-Sharp command-line parser that will allow a user to create their own parsers according to their needs.
using System;
using System.Linq;
namespace CLI_Parser
{
/// <summary>
/// This is an abstract interface class that you can inherit and create a very powerful parser using this. There's
/// no need to use any sort of if/else statements to verify and stuff. One thing you need is a basic verifier that will
/// check the user input against existing commands and then load the specific function from the user input. And if any arguments are required,
/// it will use those accordingly.
/// </summary>
public abstract class IParser
{
protected class UserCommand
{
public string cmd { get; }
public string[] args { get; }
public string strArg { get; }
public UserCommand(string input)
{
string[] data = input.Split(' ');
this.cmd = data[0].ToUpper();
if (data.Length > 1)
{
this.args = string.Join(string.Empty, data.Skip(1)).Split(' ');
}
this.strArg = (args == null || (args.Length == 1 && (args[0] == " " || args[0] == "")) ? "None" : string.Join(", ", args));
}
}
protected class Command
{
public string name { get; }
public string description { get; }
public System.Collections.Generic.List<string> arguments { get; }
public bool isPublic { get; }
public Action<object[]> function;
/// <summary>
/// This is the default constructor.
/// </summary>
/// <param name="name"></param>
/// <param name="description"></param>
/// <param name="arguments"></param>
/// <param name="isPublic"></param>
/// <param name="function"></param>
public Command(
string name,
string description,
System.Collections.Generic.List<string> arguments = null,
bool isPublic = false,
Action<object[]> function = null
)
{
this.name = name;
this.description = description;
this.arguments = arguments;
this.isPublic = isPublic;
this.function = function;
}
/// <summary>
/// Overriding the ToString method to pretty print all the information.
/// </summary>
/// <returns></returns>
public override string ToString()
{
string args = (this.arguments != null) ? (string.Join(",", this.arguments)) : "None";
return $"Name: {this.name}\nDescription: {this.description}\nArguments: {args}\nisPublic: {this.isPublic}\n=========\n";
}
}
/// <summary>
/// This method adds arguments to the current list.
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
protected System.Collections.Generic.List<string> AddArg(params string[] args)
{
var ret = new System.Collections.Generic.List<string>();
foreach (string arg in args)
ret.Add(arg);
return ret;
}
// Some default commands
protected System.Collections.Generic.List<Command> Commands = new System.Collections.Generic.List<Command>();
/// <summary>
/// This method simply checks if a key exists in the
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
protected Command hasKey(string key)
{
foreach(var cmd in Commands)
{
if (cmd.name == key)
return cmd;
}
return null;
}
protected void AddCommand(Command c)
{
Commands.Add(c);
}
protected abstract void OnLoad();
/// <summary>
/// This method will simply contain a call to OnParse method with the argument being input.
/// </summary>
/// <param name="input"></param>
public abstract void Parse(string input);
protected void OnParse(string input)
{
var uCmd = new UserCommand(input);
var data = hasKey(uCmd.cmd);
if (data == null)
{
Console.Error.WriteLine("[-] Invalid Command provided. Please \"HELP\" to check for the existing commands.");
}
else
{
if (data.function == null)
{
// We can be pretty Unhappy about this, or simply put out an error.
var msg = "Function not specified/unimplemented.";
// throw new Exception(msg);
Console.Error.WriteLine($"[-] {msg}");
}
else
{
data.function(uCmd.args);
}
}
}
/// <summary>
/// The constructor that will automatically load all the default arguments.
/// </summary>
protected IParser()
{
// Some Default Commands that will be added
AddCommand(new Command(name: "HELP", description: "Display the help menu", arguments: AddArg("--all", "-a"), isPublic: true, function: print));
AddCommand(new Command(name: "CLEAR", description: "Clear the screen", arguments: null, isPublic: false, function: clear));
AddCommand(new Command(name: "CLS", description: "Clear the screen", arguments: null, isPublic: false, function: clear));
// Load all the existing commands
OnLoad();
}
/// <summary>
/// Clear the console screen | To be invoked with CLEAR|CLS commands.
/// </summary>
protected void clear(object[] _ = null)
{
Console.Clear();
}
/// <summary>
/// Print out all the arguments that exist. The parameter (if set to true) will print out only those arguments that are set public otherwise it will
/// print out all the existing arguments.
/// Note: This method will be invoked using the HELP command.
/// </summary>
/// <param name="public_"></param>
protected void print(object[] _params = null)
{
bool public_ = (_params != null && _params.Length == 1 && _params[0].GetType() == typeof(bool));
// Display all the existing commands.
foreach (var cmd in Commands)
{
if (public_ && cmd.isPublic)
{
Console.WriteLine(cmd.ToString());
}
else
{
Console.WriteLine(cmd.ToString());
}
}
}
}
}
@TheFlash2k
Copy link
Author

TheFlash2k commented Aug 27, 2022

Basic Usage:

public class Parser : IParser
{
    // Creating a basic cmd function:
    public void cmd(object[] args = null) 
    {
        var _ = (args == null) ? -1 : args.Length;
        Console.WriteLine($"test >> {_} <<");
    }
    // Override the OnLoad method and add custom commands using this function:
    protected override void OnLoad()
    {
        AddCommand(
            new Command(
                name: "CMD",
                description: "A Very Descriptive Description",
                arguments: AddArg(
                    "args", "can", "be", "added", "but", "need", "to", "be", "parsed", "manually"
                ),
                isPublic: true,
                function: cmd
            )
        );
    }
    
    // Override the main Parse method (Although all the basic parsing has been done in the OnParse method:
    public override void Parse(string input)
    {
        base.OnParse(input);
    }

    public static void Main(string[] args) {
        Parser p = new Parser();
        p.Parse(Console.ReadLine());
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment