Foad Rezek
Foad Rezek

Reputation: 720

package for parsing argument in TCL

Does anyone know a standard package for tcl to easily parse the input arguments ? or a ready proc ? ( I have only 3 flags but something general is preferable ).

Upvotes: 3

Views: 8389

Answers (3)

betontalpfa
betontalpfa

Reputation: 3752

Here is a simple, native, no-package argument parser:

#
# arg_parse simple argument parser
# Example `arg_parse {help version} {with-value} {-with-value 123 positional arguments}`
# will return:
# `positionals {positional arguments} with-value 123`
#
# @param boolean_flags flags which does not requires additional arguments (like help)
# @param argument_flags flags which requires values (-with-value value)
# @param args the got command line arguments
#
# @return stringified array of parsed arguments
#
proc arg_parse { boolean_flags argument_flags args } {
    set argsarr(positionals) {}

    for {set i 0} {$i < [llength $args]} {incr i} {
        set arg [lindex $args $i]
        if { [sstartswith $arg "-" ] } {
            set flag [string range $arg 1 end]
            if { [lsearch $boolean_flags $flag] >= 0 } {
                set argsarr($flag) 1
            } elseif { [lsearch $argument_flags $flag] >= 0 } {
                incr i
                set argsarr($flag) [lindex $args $i]
            } else {
                puts "ERROR: Unknown flag argument: $arg"
                return
            }
        } else {
            lappend argsarr(positionals) $arg
        }
    }
    return [array get argsarr]
}

USE argument parser

#
# USE argument parser:
#
proc my_awesome_proc { args } {
    array set argsarr [arg_parse "help version" "with-value" {*}$args]
    parray argsarr
}

USE my_awesome_proc :

% my_awesome_proc -help
argsarr(help)        = 1
argsarr(positionals) = 
% my_awesome_proc -with-value 123
argsarr(positionals) = 
argsarr(with-value)  = 123
% my_awesome_proc -wrong
ERROR: Unknown flag argument: -wrong
% my_awesome_proc positional arguments
argsarr(positionals) = positional arguments
% 

Upvotes: 0

Hai Vu
Hai Vu

Reputation: 40773

The documentation includes an example. Here is a simple example:

package require cmdline

set parameters {
    {server.arg ""   "Which server to search"}
    {debug           "Turn on debugging, default=off"}
}

set usage "- A simple script to demo cmdline parsing"
array set options [cmdline::getoptions ::argv $parameters $usage]
parray options

Sample runs:

$ tclsh simple.tcl 
options(debug)  = 0
options(server) = 

$ tclsh simple.tcl -server google.com
options(debug)  = 0
options(server) = google.com

$ tclsh simple.tcl -server google.com -debug
options(debug)  = 1
options(server) = google.com

$ tclsh simple.tcl -help
simple - A simple script to demo cmdline parsing
 -server value        Which server to search <>
 -debug               Turn on debugging, default=off
 -help                Print this message
 -?                   Print this message

    while executing
"error [usage $optlist $usage]"
    (procedure "cmdline::getoptions" line 15)
    invoked from within
"cmdline::getoptions ::argv $parameters $usage"
    invoked from within
"array set options [cmdline::getoptions ::argv $parameters $usage]"
    (file "simple.tcl" line 11)

Discussion

  • Unlike most Linux utilities, TCL uses single dash instead of double dashes for command-line options
  • When a flags ends with .arg, then that flag expects an argument to follow, such as in the case of server.arg
  • The debug flag does not end with .arg, therefore it does not expect any argument
  • The user defines the command-line parameters by a list of lists. Each sub-list contains 2 or 3 parts:
    • The flag (e.g. debug)
    • The default value (e.g. 0), only if the parameter takes an argument (flag ends with .arg).
    • And the help message
  • Invoke usage/help with -help or -?, however, the output is not pretty, see the last sample run.

Update: Help/Usage

I have been thinking about the message output when the user invoke help (see the last sample run above). To get around that, you need to trap the error yourself:

set usage "- A simple script to demo cmdline parsing"
if {[catch {array set options [cmdline::getoptions ::argv $parameters $usage]}]} {
    puts [cmdline::usage $parameters $usage]
} else {
    parray options
}

Sample run 2:

$ tclsh simple.tcl -?
simple - A simple script to demo cmdline parsing
 -server value        Which server to search <>
 -debug               Turn on debugging, default=off
 -help                Print this message
 -?                   Print this message

Upvotes: 11

Peter Lewerin
Peter Lewerin

Reputation: 13282

Tcllib has such a package, cmdline. It's a bit underdocumented, but it works.

Upvotes: 2

Related Questions