Seite 1 von 1

Commandline-Helper

Verfasst: 22.02.2010 19:14
von neotoma
Da es noch immer einige gibt (wie mich), die die Commandline nutzen, und auch Tools dafür haben/erweitern/entwickeln, ist das Problem mit dem Auswerten der Parameter bekannt.
Es ist zwar nicht sehr schwer, dennoch muss man Code an verschiedenen Stellen synchron halten (Usage, Auswertung, Reaktion).
Ich habe dafür den kleinen Commandline-Helper, mit den man dies etwas besser, übersichtlicher und einfacher machen kann.

Definition der verfügbaren/bekannten Parameter:

Code: Alles auswählen

;CLI_AddOption([KURZFORM] ,[LANGFORM]    , [hat Wert (true/false) , [erlaubte werte - nur für die ausgabe] ,[Beschreibung])

;z.b. für den switch -m(in kurzform) --mode (langform) parameter encode oder decode :
 CLI_AddOption("m"  ,"mode"    ,#True ,"encode|decode" ,"Switch to a encoding or decoding mode")

;Dann Scannen der Parameter:
CLI_ScanCommandline()

;reagieren auf Parameter -h / --help - Ausgeben einer 'sprechenden ' Usage:
If CLI_HasOption("h")
   CLI_Usage()
EndIf

;Auslesen des Werten (z.b -mode encoding ... )
value.s = CLI_GetOptionValue("-m")



Code: Alles auswählen

;;===============================================================================
;; Module:      CLI_Helper.pbi
;; Version:     1,0
;; Date:        03.02.2010
;; Author:      Michael 'neotoma' Taupitz
;; TargetOS:    ALL.(i hope so...)
;; Compiler:    PureBasic >=4.4 for Windows.
;;
;; Licence:     Do as you wish with it! No warranties either implied
;;              or given... blah blah! :)
;;
;; Description
;; 
;; CLI-Helper makes the using of the Commandline-Interface much easier.
;; Instead of  walking through each parameter in your code, you can define
;; which parameters are wanted, also if they are has arguments.
;; 
;; Example:
;;
;; At first we define the wanted parameters. We have two 'names' per paremeter, a
;; ahort one r.g. 'm' was and a longer 'mode'. We can say if we expect a argument
;; and priovide a small descripetion.
;; You see, this looks much cleaner in your code:
;;
;; CLI_AddOption("m"  ,"mode"    ,#True ,"encode|decode" ,"Switch to a encoding or decoding mode")
;; CLI_AddOption("if" ,"infile"  ,#True ,"filename"      ,"Sourcefile to en/decode")
;; CLI_AddOption("of" ,"outfile" ,#True ,"filename"      ,"Destinationfile (will be overwritten)")  
;; CLI_AddOption("k"  ,"key"     ,#True ,"encryption key","Key for en/decryption")  
;; CLI_AddOption("h"  ,"help"    ,#False ,""             ,"Prints out this usage")
;; CLI_AddOption("V"  ,"version" ,#False ,""             ,"Prints out version details.")
;;
;; Next we do the scanning:
;;  CLI_ScanCommandline()
;;
;; Now we can ask if a parameter was found and do whatever we need to do.
;; ;Print Usage  
;; If CLI_HasOption("h")
;;   CLI_Usage()
;; EndIf
;;
;; The CLI_Usage is also very helpfull - it prints the possible Parameter with ther description.
;; We have also everything stored nicely in the first functions.
;;
;; 
;; The short parameter wants a '-' (-m or -h) the longer '--' (--mode or --help).
;;
;;
;; Changes / History
;;===============================================================================

CompilerIf #PB_Compiler_Version >= 440


;; - Define the information of each entry.
Structure sCliOption
  opt.s           ; short name
  longOpt.s       ; long name
  hasArgs.i       ; bool if Argument wanted
  argName.s       ; name of the argument (for usage)
  optDescription.s; description of the parameter
  optAvailable.i  ; is option available
  optValue.s      ; value of the argument
  required.i      ; bool to remember required parameters
  foundcount.i    ; count how often a option was found
EndStructure

;Here we Store the definitions
NewMap  mapOptions.sCliOption()
;Here we store the found options
NewList llOptions.sCliOption()
;This is our Error-Output.
Define CLI_ERROR_STRING.s

;; -----------------------------------------------------------------------------
;; - CLI_AddOption(opt.s, longOpt.s, hasArgs.i, argName.s, optDescription.s)
;; -----------------------------------------------------------------------------
;; - Description:
;; -  Add a allowed option to the CLI.
;; - 
;; - Parameters:
;; -  opt.s            - Short Option-Name ("m")
;; -  longOpt.s        - Long Option-Name ("mode")
;; -  hasArgs.i        - Boolean. If #True, the next entry is catched as argument
;; -  argName.s        - Name of the Argument for usage-output. ("filename")
;; -  optDescription.s - Description of the Option. Used for Usage.
;; - 
;; -----------------------------------------------------------------------------
;; - Returns: Nothing
;; - 
;;
Procedure CLI_AddOption(opt.s, longOpt.s, hasArgs.i, argName.s, optDescription.s)
  Shared mapOptions()
  mapOptions(opt)\opt = opt
  mapOptions(opt)\longOpt = longOpt
  mapOptions(opt)\hasArgs = hasArgs
  mapOptions(opt)\argName = argName
  mapOptions(opt)\optDescription = optDescription
  mapOptions(opt)\optAvailable = #False
  mapOptions(opt)\foundcount = 0
EndProcedure


;; -----------------------------------------------------------------------------
;; - CLI_ScanComandline()
;; -----------------------------------------------------------------------------
;; - Description:
;; -   Scans the Commandline. Make Sure you defined the possible options before.
;; - 
;; - Parameters:
;; - 
;; -----------------------------------------------------------------------------
;; - Returns: Nothing
;; - 
;;
Procedure CLI_ScanCommandline()
  Shared mapOptions(), llOptions()

  Protected pcount.i = CountProgramParameters()
  Protected param.s
  Protected i.i = 0
  
  While i < pcount
    param = ProgramParameter(i)
    ForEach mapOptions()
      If param = "-"+mapOptions()\opt Or  param= "--"+mapOptions()\longOpt
        AddElement( llOptions() )
        llOptions()\opt = mapOptions()\opt
        llOptions()\longOpt= mapOptions()\longOpt
        llOptions()\hasArgs= mapOptions()\hasArgs
        llOptions()\optDescription= mapOptions()\optDescription
        llOptions()\optAvailable = #True       
        mapOptions()\foundcount + 1 
        If mapOptions()\hasArgs
          i+1          
          llOptions()\optValue = ProgramParameter(i)
        EndIf
      EndIf
    Next
    
    i+1
  Wend
EndProcedure

;; -----------------------------------------------------------------------------
;; - CLI_HasOption(opt.s)
;; -----------------------------------------------------------------------------
;; - Description:
;; -   Checks if the option (opt.s) was found on the commandline
;; - 
;; - Parameters:
;; -    opt.s  - Short name of the option
;; -----------------------------------------------------------------------------
;; - Returns: #True if the Options was found, otherwise #False
;; - 
;;
Procedure.i CLI_HasOption(opt.s)
  Shared llOptions()
  Protected RetVal.i = #False
  ForEach  llOptions()  
    If llOptions()\opt = opt Or llOptions()\longOpt = opt
      RetVal = #True
      Break
    EndIf
  Next
  ProcedureReturn RetVal
EndProcedure  

;; -----------------------------------------------------------------------------
;; - CLI_GetOptionValue(opt.s)
;; -----------------------------------------------------------------------------
;; - Description:
;; -   Returns the argument of the option (opt.s).
;; - 
;; - Parameters:
;; -    opt.s  - Short name of the option
;; -----------------------------------------------------------------------------
;; - Returns: Argument of the Option
;; - 
;;
Procedure.s CLI_GetOptionValue(opt.s)
  Shared llOptions()
  ForEach  llOptions()  
    If llOptions()\opt = opt Or llOptions()\longOpt = opt
      ProcedureReturn llOptions()\optValue
    EndIf
  Next
  ProcedureReturn ""
EndProcedure  
         
;; -----------------------------------------------------------------------------
;; - CLI_SetRequired(opt.s, bReq.i = #True)  
;; -----------------------------------------------------------------------------
;; - Description:
;; -   Set the option (opt) to required.
;; - 
;; - Parameters:
;; -    opt.s  - Short name of the option
;; -    bReq.i - (optional) the Falg. if #True the Option is marked as required.
;; -----------------------------------------------------------------------------
;; - Returns: Nothing
;; - 
;;
Procedure CLI_SetRequired(opt.s, bReq.i = #True)  
  Shared mapOptions()
  If FindMapElement(mapOptions(),opt)
    mapOptions(opt)\required = bReq
  EndIf
EndProcedure

;; -----------------------------------------------------------------------------
;; - CLI_isRequired(opt.s)  
;; -----------------------------------------------------------------------------
;; - Description:
;; -   Checks if a option was required
;; - 
;; - Parameters:
;; -    opt.s  - Short name of the option
;; -----------------------------------------------------------------------------
;; - Returns: Required-Flag
;; - 
;;
Procedure CLI_isRequired(opt.s)  
  Shared mapOptions()
  ProcedureReturn mapOptions(opt)\required 
EndProcedure


;; -----------------------------------------------------------------------------
;; - CLI_CheckRequired()  
;; -----------------------------------------------------------------------------
;; - Description:
;; -   Checks if a required option was missing.
;; -   For each missed option it prompts a Info to the Commandline.
;; - 
;; -----------------------------------------------------------------------------
;; - Returns: #False if one or more required options missed
;; - 
;;
Procedure.i CLI_CheckRequired()  
  Shared mapOptions()
  Protected  retVal = #True
    
  ForEach mapOptions()
    If mapOptions()\required And mapOptions()\foundcount = 0
      Print("-"+mapOptions()\opt)
      If mapOptions()\hasArgs
        Print(" <"+mapOptions()\argName+">")
      EndIf
      Print(" is Missing!")
      PrintN("")
      retVal = #False 
    EndIf
  Next
  ProcedureReturn RetVal
EndProcedure

      
;; -----------------------------------------------------------------------------
;; - CLI_Usage()
;; -----------------------------------------------------------------------------
;; - Description:
;; -   Prints a Usage-Information to the Commandline.
;; -   The output is based on the defined Options.
;; - 
;; - Parameters:
;; -----------------------------------------------------------------------------
;; - Returns: Nothing
;; - 
;;
Procedure CLI_Usage()
  Shared mapOptions()
  Protected strTemp.s = "usage:"
  
  ForEach mapOptions()
    If mapOptions()\hasArgs
      strTemp +" [-"+mapOptions()\opt+" <"+mapOptions()\argName+">]"
    Else
      strTemp +" [-"+mapOptions()\opt+"]"
    EndIf 
  Next
  PrintN(strTemp)
  
  ForEach mapOptions()
    strTemp = " -"+mapOptions()\opt+",--"+mapOptions()\longOpt
    If mapOptions()\hasArgs
      strTemp+" <"+mapOptions()\argName+">"
    EndIf
    
    PrintN( LSet(strTemp, 40, " ") + mapOptions()\optDescription )
  Next          

EndProcedure  

;; -----------------------------------------------------------------------------
;; - CLI_HelpPrinter(Header.s, Footer.s)
;; -----------------------------------------------------------------------------
;; - Description:
;; -   Prints the Header, the Usage and Footer
;; - 
;; - Parameters:
;; -----------------------------------------------------------------------------
;; - Returns: Nothing
;; - 
;;
Procedure CLI_HelpPrinter(Header.s, Footer.s)
  PrintN(Header)
  PrintN(RSet("",Len(Header),"-"))
  PrintN("")
  CLI_Usage()
  PrintN(Footer)
  PrintN("")
EndProcedure  

CompilerElse
  CompilerError "CLI_Helper needs PureBasic 4.40 or greater. (Maps)"
CompilerEndIf

Happy coding,

Mike