Home > Delphi > Commandline controller class

Commandline controller class

While the occasions are rare, there are times when you have to isolate a piece of code in a command line application. While Delphi makes it easy to work with the command line – Embarcadero could have simplified it even more.

This is a small and effective command line controller class I wrote, that takes care of parsing parameters. Simply register your keywords with a callback procedure (anonymous of course) and voila — you can now spend your time handling options rather than parsing.

 


uses
  System.SysUtils, System.Generics.Collections;



  type

  TCMDLineController = Class(TObject)
  type
    ECMDLineController  = Class(Exception);
    TCMDLineCallback    = TProc;
  strict private
    FCommands:  TDictionary<string,tcmdlinecallback>;
  public
    Procedure   RegisterKeyword(aKeyword:String;
                const aHandler:TCMDLineCallback);virtual;
    Procedure   UnRegisterKeyword(aKeyword:String);virtual;
    Procedure   Process(Const UnknownTokenHandler:TProc);virtual;
    Constructor Create;virtual;
    Destructor  Destroy;Override;
  End;


//############################################################################
// TCMDLineController
//############################################################################

constructor TCMDLineController.Create;
begin
  inherited;
  FCommands:=TDictionary<string,tcmdlinecallback>.Create;
end;

destructor TCMDLineController.Destroy;
begin
  FCommands.Free;
  inherited;
end;

(* Purpose: Removes a keyword and callback handler from
            the commandline dictionary *)
Procedure TCMDLineController.UnRegisterKeyword(aKeyword:String);
Begin
  aKeyword:=lowercase(trim(aKeyword));
  if length(aKeyword)>0 then
  begin
    if FCommands.ContainsKey(aKeyword) then
    FCommands.Remove(aKeyword);
  end;
end;

(* Purpose: Registers a keyword and callback handler into
            the commandline controller dictionary.
            This means that whenever the controller encounters
            that keyword, the method will be called.

            In your code:
            ============

            registerKeyword('-option',
              procedure (value:String)
              begin
                showmessage('option value=' + Value);
              end );


            from the commandline:
            =====================

            >> mycommand.exe -option:someoption

            where "someoption" will be the value passed to
            your callback procedure
            *)
Procedure TCMDLineController.RegisterKeyword(aKeyword:String;
          const aHandler:TCMDLineCallback);
const
  CNT_ERR_KeywordExists =
  'Invalid commandline keyword error, keyword already exists';

  CNT_ERR_CallbackNIL =
  'Invalid commandline callback error, entrypoint was NIL';

  CNT_ERR_KeywordEmpty =
  'Invalid commandline keyword error, keyword was empty';
begin
  aKeyword:=lowercase(trim(aKeyword));
  if length(aKeyword)>0 then
  begin
    if assigned(aHandler) then
    begin
      if not FCommands.ContainsKey(aKeyword) then
      FCommands.Add(aKeyword,aHandler) else
      raise ECMDLineController.Create(CNT_ERR_KeywordExists);
    end else
    raise ECMDLineController.Create(CNT_ERR_CallbackNIL);
  end else
  Raise ECMDLineController.Create(CNT_ERR_KeywordEmpty);
end;

(* Purpose: Process the commandline parameters and match
            the values with our dictionary.
            If a keyword is not found, the unknownTokenHandler() procedure
            is called with the unknown keyword.
            Otherwise the callback handler installed for that keyword
            is called, with the value text defined for the param.

            E.g:
              mycmd.exe -somecommand:somevalue

            where -somecommand is the keyword, and somevalue is the
            string passed to the callback handler.
            The ":" character is used as a fixed separator.
            *)
procedure TCMDLineController.Process(const UnknownTokenHandler: TProc);
var
  x:  Integer;
  xpos: Integer;
  mtext:  String;
  mName:  String;
  mValue: String;
begin
  for x:=1 to System.ParamCount do
  begin
    mtext:=System.ParamStr(x);
    xpos:=pos(':',mText);
    if xpos>0 then
    begin
      mName:=copy(mtext,1,xpos-1);
      mValue:=copy(mtext,xpos+1,length(mText));
      if FCommands.ContainsKey(mName) then
      FCommands[mName](mValue) else
      if assigned(UnknownTokenHandler) then
      UnknownTokenHandler(mText);
    end else
    if assigned(UnknownTokenHandler) then
    UnknownTokenHandler(mText);
  end;
end;

Using the controller

Using the class is easy. Simply create an instance, register your keywords and callback handlers – and call process. Here is a small example of how you can use it:

  Controller:=TCMDLineController.Create;
  try

    Controller.RegisterKeyword('-input',
      procedure (aValue:String)
      begin
        writeln('Input Param set to:' + aValue);
      end);

    Controller.RegisterKeyword('-rtl',
      procedure (aValue:String)
      begin
        writeln('RTL Param set to:' + aValue);
      end);

    Controller.RegisterKeyword('-output',
      procedure (aValue:String)
      begin
        writeln('Output Param set to:' + aValue);
      end);

    Controller.RegisterKeyword('-mode',
      procedure (aValue:String)
      begin
        writeln('Mode Param set to:' + aValue);
      end);

    Controller.RegisterKeyword('-gen',
      procedure (aValue:String)
      begin
        writeln('Gen Param set to:' + aValue);
      end);

    Controller.RegisterKeyword('-help',
      procedure (aValue:String)
      begin
        DisplayHelp;
      end);

    //Now process and handle unknown keywords
    Controller.Process(procedure (aValue:String)
      Begin
        writeln('unknown keyword:' + aValue);
        DisplayHelp;
      end);

  finally
    Controller.Free;
  end;
Advertisements
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: