home *** CD-ROM | disk | FTP | other *** search
- #---------------------------------------------------------------------------
- #
- # (c) Cadre Technologies Inc. 1996
- #
- # File: %W%
- # Author: edri
- # Description: Simple command line option parser.
- #---------------------------------------------------------------------------
- # SccsId = %W% %G% Copyright 1996 Cadre Technologies Inc.
-
- #
- # Usage:
- #
- # Fill an array like this:
- #
- # set opts(<option>) { <varName> <optionType> <defaultValue> <description> }
- # ...
- #
- # Where:
- # <option> is the option string (like "-doc"),
- # <varName> is the name of a variable that will be set to the value
- # of the option,
- # <optionType> is the type of option; allowed values are "arg" or
- # "noarg"; if "arg", the named variable is set to the argument
- # following the option; if "noarg", the named variable is set to 1
- # if the option was specified, else it is set to 0.
- # <defaultValue> is the default value the variable will get if the option
- # is not specified,
- # <description> is a short string describing the option.
- #
- # <optionType>, <defaultValue> and <description> are all optional.
- #
- # Then call Options::parse with the name of the program, the name of the
- # array, and the name of the command line arguments variable (argv).
- #
- # Optionally, names of required arguments can be specified. If one or more
- # names is specified, the args array with all options removed should have
- # the same size as the number of names specified, and variables with those
- # names will be set to the corresponding argument. If no required arguments
- # are specified, the caller will have to check the remainder of the args
- # array.
- #
- # Options::parse will return an error code if an error occurred, so use
- # catch when calling Options::parse to handle this error.
- #
- # Example:
- #
- # set opts(-doc) {generate_doc noarg 0 "generate class documents"}
- # set opts(-dir) {storage_dir arg . "storage directory"}
- # set opts(-v) {verbose}
- #
- # if [catch {Options::parse climp opts argv} msg] {
- # puts stderr $msg
- # exit 1
- # }
- #
- proc Options::isOption {char} {
- if {$char == "-" || $char == "+"} {
- return 1
- }
- return 0
- }
-
- proc Options::parse {toolName optsRef argvRef args} {
- upvar $optsRef options
- upvar $argvRef argv
-
- # escape all backslashes
- regsub -all {\\} $argv {\\\\} argv
-
- # set defaults
- foreach opt [array names options] {
- set optDef $options($opt)
- set defSize [llength $optDef]
- upvar [lindex $optDef 0] var
-
- if {$defSize >= 3} {
- set var [lindex $optDef 2]
- } else {
- # default to switch option, with value "off"
- set var 0
- }
- }
-
- # parse and remove options
- while {[Options::isOption [string index [lindex $argv 0] 0]]} {
- set opt [lvarpop argv]
- if {$opt == "-help" || $opt == "-?"} {
- return -code error [Options::usage $toolName options $args]
- } elseif {$opt == "--"} {
- # end of options
- break
- }
-
- if [info exists options($opt)] {
- set optDef $options($opt)
- set defSize [llength $optDef]
- upvar [lindex $optDef 0] var
-
- if {$defSize >= 2} {
- set type [lindex $optDef 1]
- } else {
- # default to switch option, with value "off"
- set type noarg
- }
-
- if {$defSize >= 3} {
- set default [lindex $optDef 2]
- } else {
- # default to switch option, with value "off"
- set default 0
- }
-
- switch $type {
- arg { set var [lvarpop argv] }
- noarg { set var 1 }
- default { return -code error "wrong option type: $type" }
- }
- } else {
- # Check if option is an M4 option (-M4_<name>[=<value>] or
- # +M4_<name>) and parse it if caller requested it by specifing
- # "-M4" option in options.
- #
- if [info exists options(-M4)] {
- set prefix [string range $opt 1 3]
- if {$prefix == "M4_"} {
- set asn [string first "=" $opt]
- if {$asn == -1} {
- set first [string index $opt 0]
- set name [string range $opt 1 end]
- if {$first == "+"} {
- set value 1
- } else {
- set value 0
- }
- } else {
- incr asn -1
- set name [string range $opt 1 $asn]
- incr asn 2
- set value [string range $opt $asn end]
- }
-
- set optDef $options(-M4)
- upvar [lindex $optDef 0] var
- lappend var "${name}=${value}"
-
- continue
- }
- }
- set inv "ERROR: invalid option $opt\n\n"
- return -code error "$inv[Options::usage $toolName options $args]"
- }
- }
-
- set reqLen [llength $args]
- if {$reqLen > 0} {
- set argLen [llength $argv]
- if {$reqLen != $argLen} {
- set miss "ERROR: required argument missing\n\n"
- return -code error "$miss[Options::usage $toolName options $args]"
- }
-
- set i 0
- foreach arg $args {
- set s [lindex $argv $i]
- uplevel "set $arg \{$s\}"
- incr i
- }
- }
-
- return 1
- }
-
- proc Options::usage {toolName optsRef {requiredArgs ""}} {
- upvar $optsRef options
-
- set argNames "args ..."
- if {[llength $requiredArgs] > 0} {
- set argNames $requiredArgs
- }
-
- set usage "Usage: $toolName \[options] $argNames\n"
- foreach opt [lsort [array names options]] {
- set optDef $options($opt)
- set defSize [llength $optDef]
-
- if {$opt == "-M4"} {
- continue
- }
-
- if {$defSize >= 2} {
- set type [lindex $optDef 1]
- } else {
- set type noarg
- }
-
- if {$defSize >= 3 && $type != "noarg"} {
- set default " \[[lindex $optDef 2]]"
- } else {
- set default ""
- }
-
- if {$defSize >= 4} {
- set description [lindex $optDef 3]
- } else {
- set description "switch"
- }
-
- if {$type == "arg"} {
- set arg " arg"
- } else {
- set arg ""
- }
- append usage [format " %-16s : %s\n" \
- $opt$arg $description$default]
- }
- return $usage
- }
-