home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World 1998 October
/
PCWorld_1998-10_cd.bin
/
software
/
prehled
/
komix
/
DATA.Z
/
options.tcl
< prev
next >
Wrap
Text File
|
1997-11-14
|
6KB
|
219 lines
#---------------------------------------------------------------------------
#
# (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
}