67 package provide cmdline 1.3.1
69 namespace eval ::cmdline {
70 namespace export getArgv0 getopt getKnownOpt getfiles getoptions \
105 proc ::cmdline::getopt {argvVar optstring optVar valVar} {
106 upvar 1 $argvVar argsList
107 upvar 1 $optVar option
108 upvar 1 $valVar value
111 set result [
getKnownOpt argsList $optstring option value]
154 proc ::cmdline::getKnownOpt {argvVar optstring optVar valVar} {
155 upvar 1 $argvVar argsList
156 upvar 1 $optVar option
157 upvar 1 $valVar value
165 if {[
llength $argsList] != 0} {
168 switch -glob -- [
set arg [
lindex $argsList 0]] {
170 set argsList [
lrange $argsList 1 end]
174 set option [
string range $arg 1 end]
175 if {[
string equal [
string range $option 0 0] "-"]} {
176 set option [
string range $arg 2 end]
180 set idx [
string first "=" $option 1]
182 set _val [
string range $option [
expr {$idx + 1}] end]
183 set option [
string range $option 0 [
expr {$idx - 1}]]
186 if {[lsearch -exact $optstring $option] != -1} {
190 set argsList [
lrange $argsList 1 end]
191 }
elseif {[lsearch -exact $optstring "$option.arg"] != -1} {
193 set argsList [
lrange $argsList 1 end]
195 if {[
info exists _val]} {
197 }
elseif {[
llength $argsList]} {
198 set value [
lindex $argsList 0]
199 set argsList [
lrange $argsList 1 end]
201 set value "Option \"$option\" requires an argument"
206 set value "Illegal option \"-$option\""
246 proc ::cmdline::getoptions {arglistVar optlist {usage options:}} {
247 upvar 1 $arglistVar argv
251 set argc [
llength $argv]
252 while {[
set err [
getopt argv $opts opt arg]]} {
257 set result($opt) $arg
259 if {[
info exists result(?)] || [
info exists result(help)]} {
262 return [
array get result]
288 proc ::cmdline::getKnownOptions {arglistVar optlist {usage options:}} {
289 upvar 1 $arglistVar argv
298 set unknownOptions [list]
300 set argc [
llength $argv]
301 while {[
set err [
getKnownOpt argv $opts opt arg]]} {
307 lappend unknownOptions [
lindex $argv 0]
308 set argv [
lrange $argv 1 end]
310 ([
llength $argv] != 0)
311 && ![
string match "-*" [
lindex $argv 0]]
313 lappend unknownOptions [
lindex $argv 0]
314 set argv [
lrange $argv 1 end]
316 }
elseif {$err == -2} {
320 set result($opt) $arg
326 set argv [
concat $unknownOptions $argv]
328 if {[
info exists result(?)] || [
info exists result(help)]} {
331 return [
array get result]
354 proc ::cmdline::GetOptionDefaults {optlist defaultArrayVar} {
355 upvar 1 $defaultArrayVar result
358 foreach opt $optlist {
359 set name [
lindex $opt 0]
360 if {[regsub -- {\.secret$} $name {} name] == 1} {
364 if {[regsub -- {\.arg$} $name {} name] == 1} {
367 set default [
lindex $opt 1]
368 set result($name) $default
389 proc ::cmdline::usage {optlist {usage {options:}}} {
391 foreach opt [
concat $optlist \
392 {{- "Forcibly stop option processing"} {help "Print this message"} {? "Print this message"}}] {
393 set name [
lindex $opt 0]
394 if {[regsub -- {\.secret$} $name {} name] == 1} {
398 if {[regsub -- {\.arg$} $name {} name] == 1} {
399 set default [
lindex $opt 1]
400 set comment [
lindex $opt 2]
401 append str [
format " %-20s %s <%s>\n" "-$name value" \
404 set comment [
lindex $opt 1]
405 append str [
format " %-20s %s\n" "-$name" $comment]
430 proc ::cmdline::getfiles {patterns quiet} {
432 if {$::tcl_platform(platform) == "windows"} {
433 foreach pattern $patterns {
434 set pat [
file join $pattern]
435 set files [glob -nocomplain -- $pat]
438 puts stdout "warning: no files match \"$pattern\""
441 foreach file $files {
450 foreach file $result {
453 set fullPath [
file join [
pwd] $file]
455 if {[
file isfile $fullPath]} {
456 lappend files $fullPath
458 puts stdout "warning: no files match \"$file\""
476 proc ::cmdline::getArgv0 {} {
479 set name [
file tail $argv0]
480 return [
file rootname $name]
502 namespace eval ::cmdline {
503 namespace export typedGetopt typedGetoptions typedUsage
516 catch {
string is . .} charclasses
518 regexp -- {must be (.+)$} $charclasses dummy charclasses
519 regsub -all -- {, (or )?} $charclasses {|} charclasses
609 proc ::cmdline::typedGetopt {argvVar optstring optVar argVar} {
612 upvar $argvVar argsList
623 if {[
llength $argsList] != 0} {
626 switch -glob -- [
set arg [
lindex $argsList 0]] {
628 set argsList [
lrange $argsList 1 end]
635 foreach str $optstring {
636 lappend optstr [
file rootname $str]
639 set _opt [
string range $arg 1 end]
643 set opt [
lindex $optstring $i]
645 set quantifier "none"
646 if {[regexp -- {\.[^.]+([?+*])$} $opt dummy quantifier]} {
647 set opt [
string range $opt 0 end-1]
650 if {[
string first . $opt] == -1} {
653 set argsList [
lrange $argsList 1 end]
655 [regexp -- "\\.(arg|$charclasses)\$" $opt dummy charclass]
656 || [regexp -- {\.\(([^)]+)\)} $opt dummy charclass]
658 if {[
string equal arg $charclass]} {
660 }
elseif {[regexp -- "^($charclasses)\$" $charclass]} {
666 set argsList [
lrange $argsList 1 end]
667 set opt [
file rootname $opt]
671 [
llength $argsList] == 0
672 || [
string equal "--" [
lindex $argsList 0]]
674 if {[
string equal "--" [
lindex $argsList 0]]} {
675 set argsList [
lrange $argsList 1 end]
679 if {$type == "arg"} {
681 }
elseif {$type == "oneof"} {
682 set oneof ", one of $charclass"
686 if {$quantifier == "?"} {
690 }
elseif {$quantifier == "+"} {
692 if {[
llength $optarg] < 1} {
694 set optarg "Option requires at least one $charclass argument$oneof -- $opt"
698 }
elseif {$quantifier == "*"} {
702 set optarg "Option requires $charclass argument$oneof -- $opt"
708 }
elseif {($type == "arg") || (($type == "oneof") && [
string first "|[
lindex $argsList 0]|" "|$charclass|"] != -1) || (($type == "class") && [
string is $charclass [
lindex $argsList 0]])} {
711 lappend optarg [
lindex $argsList 0]
712 set argsList [
lrange $argsList 1 end]
715 if {$type == "arg"} {
717 }
elseif {$type == "oneof"} {
718 set oneof ", one of $charclass"
721 set optarg "Option requires $charclass argument$oneof -- $opt"
725 if {$quantifier == "?"} {
731 if {![regexp -- {[+*]} $quantifier]} {
737 "Illegal option type specification: must be one of $charclasses" \
741 set optarg "Illegal option -- $_opt"
809 proc ::cmdline::typedGetoptions {arglistVar optlist {usage options:}} {
812 upvar 1 $arglistVar argv
815 foreach opt $optlist {
816 set name [
lindex $opt 0]
817 if {[regsub -- {\.secret$} $name {} name] == 1} {
820 if {[regsub -- {\.multi$} $name {} name] == 1} {
823 regsub -- {\..*$} $name {} temp
827 if {[regsub -- "\\.(arg|$charclasses|\\(.+).?\$" $name {} name] == 1} {
831 set dflt [
lindex $opt 1]
833 set defaults($name) $dflt
837 set argc [
llength $argv]
838 while {[
set err [
typedGetopt argv $opts opt arg]]} {
841 [
info exists result($opt)]
842 && [
info exists multi($opt)]
849 set result($opt) "$result($opt) $arg"
852 set result($opt) "$arg"
854 }
elseif {($err == -1) || ($err == -3)} {
856 }
elseif {$err == -2 && ![
info exists defaults($opt)]} {
860 if {[
info exists result(?)] || [
info exists result(help)]} {
863 foreach {opt dflt} [
array get defaults] {
864 if {![
info exists result($opt)]} {
865 set result($opt) $dflt
868 return [
array get result]
883 proc ::cmdline::typedUsage {optlist {usage {options:}}} {
887 foreach opt [
concat $optlist \
888 {{help "Print this message"} {? "Print this message"}}] {
889 set name [
lindex $opt 0]
890 if {[regsub -- {\.secret$} $name {} name] == 1} {
893 if {[regsub -- {\.multi$} $name {} name] == 1} {
898 [regexp -- "\\.(arg|$charclasses)\$" $name dummy charclass]
899 || [regexp -- {\.\(([^)]+)\)} $opt dummy charclass]
901 regsub -- "\\..+\$" $name {} name
902 set comment [
lindex $opt 2]
903 set default "<[
lindex $opt 1]>"
904 if {$default == "<>"} {
907 append str [
format " %-20s %s %s\n" "-$name $charclass" \
910 set comment [
lindex $opt 1]
911 append str [
format " %-20s %s\n" "-$name" $comment]
932 proc ::cmdline::prefixSearch {list pattern} {
935 if {[
set pos [::lsearch -exact $list $pattern]] > -1} {
941 set slist [lsort $list]
942 if {[
set pos [::lsearch -glob $slist $pattern*]] > -1} {
945 set check [
lindex $slist [
expr {$pos + 1}]]
946 if {[
string first $pattern $check] != 0} {
947 return [::lsearch -exact $list [
lindex $slist $pos]]
964 proc ::cmdline::Error {message args} {
965 return -code error -errorcode [
linsert $args 0 CMDLINE] $message