diff CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/tcl8.6/opt0.4/optparse.tcl @ 68:5028fdace37b

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 16:23:26 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/tcl8.6/opt0.4/optparse.tcl	Tue Mar 18 16:23:26 2025 -0400
@@ -0,0 +1,1072 @@
+# optparse.tcl --
+#
+#       (private) Option parsing package
+#       Primarily used internally by the safe:: code.
+#
+#	WARNING: This code will go away in a future release
+#	of Tcl.  It is NOT supported and you should not rely
+#	on it.  If your code does rely on this package you
+#	may directly incorporate this code into your application.
+
+package require Tcl 8.5-
+# When this version number changes, update the pkgIndex.tcl file
+# and the install directory in the Makefiles.
+package provide opt 0.4.8
+
+namespace eval ::tcl {
+
+    # Exported APIs
+    namespace export OptKeyRegister OptKeyDelete OptKeyError OptKeyParse \
+             OptProc OptProcArgGiven OptParse \
+	     Lempty Lget \
+             Lassign Lvarpop Lvarpop1 Lvarset Lvarincr \
+             SetMax SetMin
+
+
+#################  Example of use / 'user documentation'  ###################
+
+    proc OptCreateTestProc {} {
+
+	# Defines ::tcl::OptParseTest as a test proc with parsed arguments
+	# (can't be defined before the code below is loaded (before "OptProc"))
+
+	# Every OptProc give usage information on "procname -help".
+	# Try "tcl::OptParseTest -help" and "tcl::OptParseTest -a" and
+	# then other arguments.
+	#
+	# example of 'valid' call:
+	# ::tcl::OptParseTest save -4 -pr 23 -libsok SybTcl\
+	#		-nostatics false ch1
+	OptProc OptParseTest {
+            {subcommand -choice {save print} "sub command"}
+            {arg1 3 "some number"}
+            {-aflag}
+            {-intflag      7}
+            {-weirdflag                    "help string"}
+            {-noStatics                    "Not ok to load static packages"}
+            {-nestedloading1 true           "OK to load into nested children"}
+            {-nestedloading2 -boolean true "OK to load into nested children"}
+            {-libsOK        -choice {Tk SybTcl}
+		                      "List of packages that can be loaded"}
+            {-precision     -int 12        "Number of digits of precision"}
+            {-intval        7               "An integer"}
+            {-scale         -float 1.0     "Scale factor"}
+            {-zoom          1.0             "Zoom factor"}
+            {-arbitrary     foobar          "Arbitrary string"}
+            {-random        -string 12   "Random string"}
+            {-listval       -list {}       "List value"}
+            {-blahflag       -blah abc       "Funny type"}
+	    {arg2 -boolean "a boolean"}
+	    {arg3 -choice "ch1 ch2"}
+	    {?optarg? -list {} "optional argument"}
+        } {
+	    foreach v [info locals] {
+		puts stderr [format "%14s : %s" $v [set $v]]
+	    }
+	}
+    }
+
+###################  No User serviceable part below ! ###############
+
+    # Array storing the parsed descriptions
+    variable OptDesc
+    array set OptDesc {}
+    # Next potentially free key id (numeric)
+    variable OptDescN 0
+
+# Inside algorithm/mechanism description:
+# (not for the faint hearted ;-)
+#
+# The argument description is parsed into a "program tree"
+# It is called a "program" because it is the program used by
+# the state machine interpreter that use that program to
+# actually parse the arguments at run time.
+#
+# The general structure of a "program" is
+# notation (pseudo bnf like)
+#    name :== definition        defines "name" as being "definition"
+#    { x y z }                  means list of x, y, and z
+#    x*                         means x repeated 0 or more time
+#    x+                         means "x x*"
+#    x?                         means optionally x
+#    x | y                      means x or y
+#    "cccc"                     means the literal string
+#
+#    program        :== { programCounter programStep* }
+#
+#    programStep    :== program | singleStep
+#
+#    programCounter :== {"P" integer+ }
+#
+#    singleStep     :== { instruction parameters* }
+#
+#    instruction    :== single element list
+#
+# (the difference between singleStep and program is that \
+#   llength [lindex $program 0] >= 2
+# while
+#   llength [lindex $singleStep 0] == 1
+# )
+#
+# And for this application:
+#
+#    singleStep     :== { instruction varname {hasBeenSet currentValue} type
+#                         typeArgs help }
+#    instruction    :== "flags" | "value"
+#    type           :== knowType | anyword
+#    knowType       :== "string" | "int" | "boolean" | "boolflag" | "float"
+#                       | "choice"
+#
+# for type "choice" typeArgs is a list of possible choices, the first one
+# is the default value. for all other types the typeArgs is the default value
+#
+# a "boolflag" is the type for a flag whose presence or absence, without
+# additional arguments means respectively true or false (default flag type).
+#
+# programCounter is the index in the list of the currently processed
+# programStep (thus starting at 1 (0 is {"P" prgCounterValue}).
+# If it is a list it points toward each currently selected programStep.
+# (like for "flags", as they are optional, form a set and programStep).
+
+# Performance/Implementation issues
+# ---------------------------------
+# We use tcl lists instead of arrays because with tcl8.0
+# they should start to be much faster.
+# But this code use a lot of helper procs (like Lvarset)
+# which are quite slow and would be helpfully optimized
+# for instance by being written in C. Also our struture
+# is complex and there is maybe some places where the
+# string rep might be calculated at great exense. to be checked.
+
+#
+# Parse a given description and saves it here under the given key
+# generate a unused keyid if not given
+#
+proc ::tcl::OptKeyRegister {desc {key ""}} {
+    variable OptDesc
+    variable OptDescN
+    if {[string equal $key ""]} {
+        # in case a key given to us as a parameter was a number
+        while {[info exists OptDesc($OptDescN)]} {incr OptDescN}
+        set key $OptDescN
+        incr OptDescN
+    }
+    # program counter
+    set program [list [list "P" 1]]
+
+    # are we processing flags (which makes a single program step)
+    set inflags 0
+
+    set state {}
+
+    # flag used to detect that we just have a single (flags set) subprogram.
+    set empty 1
+
+    foreach item $desc {
+	if {$state == "args"} {
+	    # more items after 'args'...
+	    return -code error "'args' special argument must be the last one"
+	}
+        set res [OptNormalizeOne $item]
+        set state [lindex $res 0]
+        if {$inflags} {
+            if {$state == "flags"} {
+		# add to 'subprogram'
+                lappend flagsprg $res
+            } else {
+                # put in the flags
+                # structure for flag programs items is a list of
+                # {subprgcounter {prg flag 1} {prg flag 2} {...}}
+                lappend program $flagsprg
+                # put the other regular stuff
+                lappend program $res
+		set inflags 0
+		set empty 0
+            }
+        } else {
+           if {$state == "flags"} {
+               set inflags 1
+               # sub program counter + first sub program
+               set flagsprg [list [list "P" 1] $res]
+           } else {
+               lappend program $res
+               set empty 0
+           }
+       }
+   }
+   if {$inflags} {
+       if {$empty} {
+	   # We just have the subprogram, optimize and remove
+	   # unneeded level:
+	   set program $flagsprg
+       } else {
+	   lappend program $flagsprg
+       }
+   }
+
+   set OptDesc($key) $program
+
+   return $key
+}
+
+#
+# Free the storage for that given key
+#
+proc ::tcl::OptKeyDelete {key} {
+    variable OptDesc
+    unset OptDesc($key)
+}
+
+    # Get the parsed description stored under the given key.
+    proc OptKeyGetDesc {descKey} {
+        variable OptDesc
+        if {![info exists OptDesc($descKey)]} {
+            return -code error "Unknown option description key \"$descKey\""
+        }
+        set OptDesc($descKey)
+    }
+
+# Parse entry point for ppl who don't want to register with a key,
+# for instance because the description changes dynamically.
+#  (otherwise one should really use OptKeyRegister once + OptKeyParse
+#   as it is way faster or simply OptProc which does it all)
+# Assign a temporary key, call OptKeyParse and then free the storage
+proc ::tcl::OptParse {desc arglist} {
+    set tempkey [OptKeyRegister $desc]
+    set ret [catch {uplevel 1 [list ::tcl::OptKeyParse $tempkey $arglist]} res]
+    OptKeyDelete $tempkey
+    return -code $ret $res
+}
+
+# Helper function, replacement for proc that both
+# register the description under a key which is the name of the proc
+# (and thus unique to that code)
+# and add a first line to the code to call the OptKeyParse proc
+# Stores the list of variables that have been actually given by the user
+# (the other will be sets to their default value)
+# into local variable named "Args".
+proc ::tcl::OptProc {name desc body} {
+    set namespace [uplevel 1 [list ::namespace current]]
+    if {[string match "::*" $name] || [string equal $namespace "::"]} {
+        # absolute name or global namespace, name is the key
+        set key $name
+    } else {
+        # we are relative to some non top level namespace:
+        set key "${namespace}::${name}"
+    }
+    OptKeyRegister $desc $key
+    uplevel 1 [list ::proc $name args "set Args \[::tcl::OptKeyParse $key \$args\]\n$body"]
+    return $key
+}
+# Check that a argument has been given
+# assumes that "OptProc" has been used as it will check in "Args" list
+proc ::tcl::OptProcArgGiven {argname} {
+    upvar Args alist
+    expr {[lsearch $alist $argname] >=0}
+}
+
+    #######
+    # Programs/Descriptions manipulation
+
+    # Return the instruction word/list of a given step/(sub)program
+    proc OptInstr {lst} {
+	lindex $lst 0
+    }
+    # Is a (sub) program or a plain instruction ?
+    proc OptIsPrg {lst} {
+	expr {[llength [OptInstr $lst]]>=2}
+    }
+    # Is this instruction a program counter or a real instr
+    proc OptIsCounter {item} {
+	expr {[lindex $item 0]=="P"}
+    }
+    # Current program counter (2nd word of first word)
+    proc OptGetPrgCounter {lst} {
+	Lget $lst {0 1}
+    }
+    # Current program counter (2nd word of first word)
+    proc OptSetPrgCounter {lstName newValue} {
+	upvar $lstName lst
+	set lst [lreplace $lst 0 0 [concat "P" $newValue]]
+    }
+    # returns a list of currently selected items.
+    proc OptSelection {lst} {
+	set res {}
+	foreach idx [lrange [lindex $lst 0] 1 end] {
+	    lappend res [Lget $lst $idx]
+	}
+	return $res
+    }
+
+    # Advance to next description
+    proc OptNextDesc {descName} {
+        uplevel 1 [list Lvarincr $descName {0 1}]
+    }
+
+    # Get the current description, eventually descend
+    proc OptCurDesc {descriptions} {
+        lindex $descriptions [OptGetPrgCounter $descriptions]
+    }
+    # get the current description, eventually descend
+    # through sub programs as needed.
+    proc OptCurDescFinal {descriptions} {
+        set item [OptCurDesc $descriptions]
+	# Descend untill we get the actual item and not a sub program
+        while {[OptIsPrg $item]} {
+            set item [OptCurDesc $item]
+        }
+	return $item
+    }
+    # Current final instruction adress
+    proc OptCurAddr {descriptions {start {}}} {
+	set adress [OptGetPrgCounter $descriptions]
+	lappend start $adress
+	set item [lindex $descriptions $adress]
+	if {[OptIsPrg $item]} {
+	    return [OptCurAddr $item $start]
+	} else {
+	    return $start
+	}
+    }
+    # Set the value field of the current instruction
+    proc OptCurSetValue {descriptionsName value} {
+	upvar $descriptionsName descriptions
+	# get the current item full adress
+        set adress [OptCurAddr $descriptions]
+	# use the 3th field of the item  (see OptValue / OptNewInst)
+	lappend adress 2
+	Lvarset descriptions $adress [list 1 $value]
+	#                                  ^hasBeenSet flag
+    }
+
+    # empty state means done/paste the end of the program
+    proc OptState {item} {
+        lindex $item 0
+    }
+
+    # current state
+    proc OptCurState {descriptions} {
+        OptState [OptCurDesc $descriptions]
+    }
+
+    #######
+    # Arguments manipulation
+
+    # Returns the argument that has to be processed now
+    proc OptCurrentArg {lst} {
+        lindex $lst 0
+    }
+    # Advance to next argument
+    proc OptNextArg {argsName} {
+        uplevel 1 [list Lvarpop1 $argsName]
+    }
+    #######
+
+
+
+
+
+    # Loop over all descriptions, calling OptDoOne which will
+    # eventually eat all the arguments.
+    proc OptDoAll {descriptionsName argumentsName} {
+	upvar $descriptionsName descriptions
+	upvar $argumentsName arguments
+#	puts "entered DoAll"
+	# Nb: the places where "state" can be set are tricky to figure
+	#     because DoOne sets the state to flagsValue and return -continue
+	#     when needed...
+	set state [OptCurState $descriptions]
+	# We'll exit the loop in "OptDoOne" or when state is empty.
+        while 1 {
+	    set curitem [OptCurDesc $descriptions]
+	    # Do subprograms if needed, call ourselves on the sub branch
+	    while {[OptIsPrg $curitem]} {
+		OptDoAll curitem arguments
+#		puts "done DoAll sub"
+		# Insert back the results in current tree
+		Lvarset1nc descriptions [OptGetPrgCounter $descriptions]\
+			$curitem
+		OptNextDesc descriptions
+		set curitem [OptCurDesc $descriptions]
+                set state [OptCurState $descriptions]
+	    }
+#           puts "state = \"$state\" - arguments=($arguments)"
+	    if {[Lempty $state]} {
+		# Nothing left to do, we are done in this branch:
+		break
+	    }
+	    # The following statement can make us terminate/continue
+	    # as it use return -code {break, continue, return and error}
+	    # codes
+            OptDoOne descriptions state arguments
+	    # If we are here, no special return code where issued,
+	    # we'll step to next instruction :
+#           puts "new state  = \"$state\""
+	    OptNextDesc descriptions
+	    set state [OptCurState $descriptions]
+        }
+    }
+
+    # Process one step for the state machine,
+    # eventually consuming the current argument.
+    proc OptDoOne {descriptionsName stateName argumentsName} {
+        upvar $argumentsName arguments
+        upvar $descriptionsName descriptions
+	upvar $stateName state
+
+	# the special state/instruction "args" eats all
+	# the remaining args (if any)
+	if {($state == "args")} {
+	    if {![Lempty $arguments]} {
+		# If there is no additional arguments, leave the default value
+		# in.
+		OptCurSetValue descriptions $arguments
+		set arguments {}
+	    }
+#            puts "breaking out ('args' state: consuming every reminding args)"
+	    return -code break
+	}
+
+	if {[Lempty $arguments]} {
+	    if {$state == "flags"} {
+		# no argument and no flags : we're done
+#                puts "returning to previous (sub)prg (no more args)"
+		return -code return
+	    } elseif {$state == "optValue"} {
+		set state next; # not used, for debug only
+		# go to next state
+		return
+	    } else {
+		return -code error [OptMissingValue $descriptions]
+	    }
+	} else {
+	    set arg [OptCurrentArg $arguments]
+	}
+
+        switch $state {
+            flags {
+                # A non-dash argument terminates the options, as does --
+
+                # Still a flag ?
+                if {![OptIsFlag $arg]} {
+                    # don't consume the argument, return to previous prg
+                    return -code return
+                }
+                # consume the flag
+                OptNextArg arguments
+                if {[string equal "--" $arg]} {
+                    # return from 'flags' state
+                    return -code return
+                }
+
+                set hits [OptHits descriptions $arg]
+                if {$hits > 1} {
+                    return -code error [OptAmbigous $descriptions $arg]
+                } elseif {$hits == 0} {
+                    return -code error [OptFlagUsage $descriptions $arg]
+                }
+		set item [OptCurDesc $descriptions]
+                if {[OptNeedValue $item]} {
+		    # we need a value, next state is
+		    set state flagValue
+                } else {
+                    OptCurSetValue descriptions 1
+                }
+		# continue
+		return -code continue
+            }
+	    flagValue -
+	    value {
+		set item [OptCurDesc $descriptions]
+                # Test the values against their required type
+		if {[catch {OptCheckType $arg\
+			[OptType $item] [OptTypeArgs $item]} val]} {
+		    return -code error [OptBadValue $item $arg $val]
+		}
+                # consume the value
+                OptNextArg arguments
+		# set the value
+		OptCurSetValue descriptions $val
+		# go to next state
+		if {$state == "flagValue"} {
+		    set state flags
+		    return -code continue
+		} else {
+		    set state next; # not used, for debug only
+		    return ; # will go on next step
+		}
+	    }
+	    optValue {
+		set item [OptCurDesc $descriptions]
+                # Test the values against their required type
+		if {![catch {OptCheckType $arg\
+			[OptType $item] [OptTypeArgs $item]} val]} {
+		    # right type, so :
+		    # consume the value
+		    OptNextArg arguments
+		    # set the value
+		    OptCurSetValue descriptions $val
+		}
+		# go to next state
+		set state next; # not used, for debug only
+		return ; # will go on next step
+	    }
+        }
+	# If we reach this point: an unknown
+	# state as been entered !
+	return -code error "Bug! unknown state in DoOne \"$state\"\
+		(prg counter [OptGetPrgCounter $descriptions]:\
+			[OptCurDesc $descriptions])"
+    }
+
+# Parse the options given the key to previously registered description
+# and arguments list
+proc ::tcl::OptKeyParse {descKey arglist} {
+
+    set desc [OptKeyGetDesc $descKey]
+
+    # make sure -help always give usage
+    if {[string equal -nocase "-help" $arglist]} {
+	return -code error [OptError "Usage information:" $desc 1]
+    }
+
+    OptDoAll desc arglist
+
+    if {![Lempty $arglist]} {
+	return -code error [OptTooManyArgs $desc $arglist]
+    }
+
+    # Analyse the result
+    # Walk through the tree:
+    OptTreeVars $desc "#[expr {[info level]-1}]"
+}
+
+    # determine string length for nice tabulated output
+    proc OptTreeVars {desc level {vnamesLst {}}} {
+	foreach item $desc {
+	    if {[OptIsCounter $item]} continue
+	    if {[OptIsPrg $item]} {
+		set vnamesLst [OptTreeVars $item $level $vnamesLst]
+	    } else {
+		set vname [OptVarName $item]
+		upvar $level $vname var
+		if {[OptHasBeenSet $item]} {
+#		    puts "adding $vname"
+		    # lets use the input name for the returned list
+		    # it is more usefull, for instance you can check that
+		    # no flags at all was given with expr
+		    # {![string match "*-*" $Args]}
+		    lappend vnamesLst [OptName $item]
+		    set var [OptValue $item]
+		} else {
+		    set var [OptDefaultValue $item]
+		}
+	    }
+	}
+	return $vnamesLst
+    }
+
+
+# Check the type of a value
+# and emit an error if arg is not of the correct type
+# otherwise returns the canonical value of that arg (ie 0/1 for booleans)
+proc ::tcl::OptCheckType {arg type {typeArgs ""}} {
+#    puts "checking '$arg' against '$type' ($typeArgs)"
+
+    # only types "any", "choice", and numbers can have leading "-"
+
+    switch -exact -- $type {
+        int {
+            if {![string is integer -strict $arg]} {
+                error "not an integer"
+            }
+	    return $arg
+        }
+        float {
+            return [expr {double($arg)}]
+        }
+	script -
+        list {
+	    # if llength fail : malformed list
+            if {[llength $arg]==0 && [OptIsFlag $arg]} {
+		error "no values with leading -"
+	    }
+	    return $arg
+        }
+        boolean {
+	    if {![string is boolean -strict $arg]} {
+		error "non canonic boolean"
+            }
+	    # convert true/false because expr/if is broken with "!,...
+	    return [expr {$arg ? 1 : 0}]
+        }
+        choice {
+            if {$arg ni $typeArgs} {
+                error "invalid choice"
+            }
+	    return $arg
+        }
+	any {
+	    return $arg
+	}
+	string -
+	default {
+            if {[OptIsFlag $arg]} {
+                error "no values with leading -"
+            }
+	    return $arg
+        }
+    }
+    return neverReached
+}
+
+    # internal utilities
+
+    # returns the number of flags matching the given arg
+    # sets the (local) prg counter to the list of matches
+    proc OptHits {descName arg} {
+        upvar $descName desc
+        set hits 0
+        set hitems {}
+	set i 1
+
+	set larg [string tolower $arg]
+	set len  [string length $larg]
+	set last [expr {$len-1}]
+
+        foreach item [lrange $desc 1 end] {
+            set flag [OptName $item]
+	    # lets try to match case insensitively
+	    # (string length ought to be cheap)
+	    set lflag [string tolower $flag]
+	    if {$len == [string length $lflag]} {
+		if {[string equal $larg $lflag]} {
+		    # Exact match case
+		    OptSetPrgCounter desc $i
+		    return 1
+		}
+	    } elseif {[string equal $larg [string range $lflag 0 $last]]} {
+		lappend hitems $i
+		incr hits
+            }
+	    incr i
+        }
+	if {$hits} {
+	    OptSetPrgCounter desc $hitems
+	}
+        return $hits
+    }
+
+    # Extract fields from the list structure:
+
+    proc OptName {item} {
+        lindex $item 1
+    }
+    proc OptHasBeenSet {item} {
+	Lget $item {2 0}
+    }
+    proc OptValue {item} {
+	Lget $item {2 1}
+    }
+
+    proc OptIsFlag {name} {
+        string match "-*" $name
+    }
+    proc OptIsOpt {name} {
+        string match {\?*} $name
+    }
+    proc OptVarName {item} {
+        set name [OptName $item]
+        if {[OptIsFlag $name]} {
+            return [string range $name 1 end]
+        } elseif {[OptIsOpt $name]} {
+	    return [string trim $name "?"]
+	} else {
+            return $name
+        }
+    }
+    proc OptType {item} {
+        lindex $item 3
+    }
+    proc OptTypeArgs {item} {
+        lindex $item 4
+    }
+    proc OptHelp {item} {
+        lindex $item 5
+    }
+    proc OptNeedValue {item} {
+        expr {![string equal [OptType $item] boolflag]}
+    }
+    proc OptDefaultValue {item} {
+        set val [OptTypeArgs $item]
+        switch -exact -- [OptType $item] {
+            choice {return [lindex $val 0]}
+	    boolean -
+	    boolflag {
+		# convert back false/true to 0/1 because expr !$bool
+		# is broken..
+		if {$val} {
+		    return 1
+		} else {
+		    return 0
+		}
+	    }
+        }
+        return $val
+    }
+
+    # Description format error helper
+    proc OptOptUsage {item {what ""}} {
+        return -code error "invalid description format$what: $item\n\
+                should be a list of {varname|-flagname ?-type? ?defaultvalue?\
+                ?helpstring?}"
+    }
+
+
+    # Generate a canonical form single instruction
+    proc OptNewInst {state varname type typeArgs help} {
+	list $state $varname [list 0 {}] $type $typeArgs $help
+	#                          ^  ^
+	#                          |  |
+	#               hasBeenSet=+  +=currentValue
+    }
+
+    # Translate one item to canonical form
+    proc OptNormalizeOne {item} {
+        set lg [Lassign $item varname arg1 arg2 arg3]
+#       puts "called optnormalizeone '$item' v=($varname), lg=$lg"
+        set isflag [OptIsFlag $varname]
+	set isopt  [OptIsOpt  $varname]
+        if {$isflag} {
+            set state "flags"
+        } elseif {$isopt} {
+	    set state "optValue"
+	} elseif {![string equal $varname "args"]} {
+	    set state "value"
+	} else {
+	    set state "args"
+	}
+
+	# apply 'smart' 'fuzzy' logic to try to make
+	# description writer's life easy, and our's difficult :
+	# let's guess the missing arguments :-)
+
+        switch $lg {
+            1 {
+                if {$isflag} {
+                    return [OptNewInst $state $varname boolflag false ""]
+                } else {
+                    return [OptNewInst $state $varname any "" ""]
+                }
+            }
+            2 {
+                # varname default
+                # varname help
+                set type [OptGuessType $arg1]
+                if {[string equal $type "string"]} {
+                    if {$isflag} {
+			set type boolflag
+			set def false
+		    } else {
+			set type any
+			set def ""
+		    }
+		    set help $arg1
+                } else {
+                    set help ""
+                    set def $arg1
+                }
+                return [OptNewInst $state $varname $type $def $help]
+            }
+            3 {
+                # varname type value
+                # varname value comment
+
+                if {[regexp {^-(.+)$} $arg1 x type]} {
+		    # flags/optValue as they are optional, need a "value",
+		    # on the contrary, for a variable (non optional),
+	            # default value is pointless, 'cept for choices :
+		    if {$isflag || $isopt || ($type == "choice")} {
+			return [OptNewInst $state $varname $type $arg2 ""]
+		    } else {
+			return [OptNewInst $state $varname $type "" $arg2]
+		    }
+                } else {
+                    return [OptNewInst $state $varname\
+			    [OptGuessType $arg1] $arg1 $arg2]
+                }
+            }
+            4 {
+                if {[regexp {^-(.+)$} $arg1 x type]} {
+		    return [OptNewInst $state $varname $type $arg2 $arg3]
+                } else {
+                    return -code error [OptOptUsage $item]
+                }
+            }
+            default {
+                return -code error [OptOptUsage $item]
+            }
+        }
+    }
+
+    # Auto magic lazy type determination
+    proc OptGuessType {arg} {
+ 	 if { $arg == "true" || $arg == "false" } {
+            return boolean
+        }
+        if {[string is integer -strict $arg]} {
+            return int
+        }
+        if {[string is double -strict $arg]} {
+            return float
+        }
+        return string
+    }
+
+    # Error messages front ends
+
+    proc OptAmbigous {desc arg} {
+        OptError "ambigous option \"$arg\", choose from:" [OptSelection $desc]
+    }
+    proc OptFlagUsage {desc arg} {
+        OptError "bad flag \"$arg\", must be one of" $desc
+    }
+    proc OptTooManyArgs {desc arguments} {
+        OptError "too many arguments (unexpected argument(s): $arguments),\
+		usage:"\
+		$desc 1
+    }
+    proc OptParamType {item} {
+	if {[OptIsFlag $item]} {
+	    return "flag"
+	} else {
+	    return "parameter"
+	}
+    }
+    proc OptBadValue {item arg {err {}}} {
+#       puts "bad val err = \"$err\""
+        OptError "bad value \"$arg\" for [OptParamType $item]"\
+		[list $item]
+    }
+    proc OptMissingValue {descriptions} {
+#        set item [OptCurDescFinal $descriptions]
+        set item [OptCurDesc $descriptions]
+        OptError "no value given for [OptParamType $item] \"[OptName $item]\"\
+		(use -help for full usage) :"\
+		[list $item]
+    }
+
+proc ::tcl::OptKeyError {prefix descKey {header 0}} {
+    OptError $prefix [OptKeyGetDesc $descKey] $header
+}
+
+    # determine string length for nice tabulated output
+    proc OptLengths {desc nlName tlName dlName} {
+	upvar $nlName nl
+	upvar $tlName tl
+	upvar $dlName dl
+	foreach item $desc {
+	    if {[OptIsCounter $item]} continue
+	    if {[OptIsPrg $item]} {
+		OptLengths $item nl tl dl
+	    } else {
+		SetMax nl [string length [OptName $item]]
+		SetMax tl [string length [OptType $item]]
+		set dv [OptTypeArgs $item]
+		if {[OptState $item] != "header"} {
+		    set dv "($dv)"
+		}
+		set l [string length $dv]
+		# limit the space allocated to potentially big "choices"
+		if {([OptType $item] != "choice") || ($l<=12)} {
+		    SetMax dl $l
+		} else {
+		    if {![info exists dl]} {
+			set dl 0
+		    }
+		}
+	    }
+	}
+    }
+    # output the tree
+    proc OptTree {desc nl tl dl} {
+	set res ""
+	foreach item $desc {
+	    if {[OptIsCounter $item]} continue
+	    if {[OptIsPrg $item]} {
+		append res [OptTree $item $nl $tl $dl]
+	    } else {
+		set dv [OptTypeArgs $item]
+		if {[OptState $item] != "header"} {
+		    set dv "($dv)"
+		}
+		append res [string trimright [format "\n    %-*s %-*s %-*s %s" \
+			$nl [OptName $item] $tl [OptType $item] \
+			$dl $dv [OptHelp $item]]]
+	    }
+	}
+	return $res
+    }
+
+# Give nice usage string
+proc ::tcl::OptError {prefix desc {header 0}} {
+    # determine length
+    if {$header} {
+	# add faked instruction
+	set h [list [OptNewInst header Var/FlagName Type Value Help]]
+	lappend h   [OptNewInst header ------------ ---- ----- ----]
+	lappend h   [OptNewInst header {(-help} "" "" {gives this help)}]
+	set desc [concat $h $desc]
+    }
+    OptLengths $desc nl tl dl
+    # actually output
+    return "$prefix[OptTree $desc $nl $tl $dl]"
+}
+
+
+################     General Utility functions   #######################
+
+#
+# List utility functions
+# Naming convention:
+#     "Lvarxxx" take the list VARiable name as argument
+#     "Lxxxx"   take the list value as argument
+#               (which is not costly with Tcl8 objects system
+#                as it's still a reference and not a copy of the values)
+#
+
+# Is that list empty ?
+proc ::tcl::Lempty {list} {
+    expr {[llength $list]==0}
+}
+
+# Gets the value of one leaf of a lists tree
+proc ::tcl::Lget {list indexLst} {
+    if {[llength $indexLst] <= 1} {
+        return [lindex $list $indexLst]
+    }
+    Lget [lindex $list [lindex $indexLst 0]] [lrange $indexLst 1 end]
+}
+# Sets the value of one leaf of a lists tree
+# (we use the version that does not create the elements because
+#  it would be even slower... needs to be written in C !)
+# (nb: there is a non trivial recursive problem with indexes 0,
+#  which appear because there is no difference between a list
+#  of 1 element and 1 element alone : [list "a"] == "a" while
+#  it should be {a} and [listp a] should be 0 while [listp {a b}] would be 1
+#  and [listp "a b"] maybe 0. listp does not exist either...)
+proc ::tcl::Lvarset {listName indexLst newValue} {
+    upvar $listName list
+    if {[llength $indexLst] <= 1} {
+        Lvarset1nc list $indexLst $newValue
+    } else {
+        set idx [lindex $indexLst 0]
+        set targetList [lindex $list $idx]
+        # reduce refcount on targetList (not really usefull now,
+	# could be with optimizing compiler)
+#        Lvarset1 list $idx {}
+        # recursively replace in targetList
+        Lvarset targetList [lrange $indexLst 1 end] $newValue
+        # put updated sub list back in the tree
+        Lvarset1nc list $idx $targetList
+    }
+}
+# Set one cell to a value, eventually create all the needed elements
+# (on level-1 of lists)
+variable emptyList {}
+proc ::tcl::Lvarset1 {listName index newValue} {
+    upvar $listName list
+    if {$index < 0} {return -code error "invalid negative index"}
+    set lg [llength $list]
+    if {$index >= $lg} {
+        variable emptyList
+        for {set i $lg} {$i<$index} {incr i} {
+            lappend list $emptyList
+        }
+        lappend list $newValue
+    } else {
+        set list [lreplace $list $index $index $newValue]
+    }
+}
+# same as Lvarset1 but no bound checking / creation
+proc ::tcl::Lvarset1nc {listName index newValue} {
+    upvar $listName list
+    set list [lreplace $list $index $index $newValue]
+}
+# Increments the value of one leaf of a lists tree
+# (which must exists)
+proc ::tcl::Lvarincr {listName indexLst {howMuch 1}} {
+    upvar $listName list
+    if {[llength $indexLst] <= 1} {
+        Lvarincr1 list $indexLst $howMuch
+    } else {
+        set idx [lindex $indexLst 0]
+        set targetList [lindex $list $idx]
+        # reduce refcount on targetList
+        Lvarset1nc list $idx {}
+        # recursively replace in targetList
+        Lvarincr targetList [lrange $indexLst 1 end] $howMuch
+        # put updated sub list back in the tree
+        Lvarset1nc list $idx $targetList
+    }
+}
+# Increments the value of one cell of a list
+proc ::tcl::Lvarincr1 {listName index {howMuch 1}} {
+    upvar $listName list
+    set newValue [expr {[lindex $list $index]+$howMuch}]
+    set list [lreplace $list $index $index $newValue]
+    return $newValue
+}
+# Removes the first element of a list
+# and returns the new list value
+proc ::tcl::Lvarpop1 {listName} {
+    upvar $listName list
+    set list [lrange $list 1 end]
+}
+# Same but returns the removed element
+# (Like the tclX version)
+proc ::tcl::Lvarpop {listName} {
+    upvar $listName list
+    set el [lindex $list 0]
+    set list [lrange $list 1 end]
+    return $el
+}
+# Assign list elements to variables and return the length of the list
+proc ::tcl::Lassign {list args} {
+    # faster than direct blown foreach (which does not byte compile)
+    set i 0
+    set lg [llength $list]
+    foreach vname $args {
+        if {$i>=$lg} break
+        uplevel 1 [list ::set $vname [lindex $list $i]]
+        incr i
+    }
+    return $lg
+}
+
+# Misc utilities
+
+# Set the varname to value if value is greater than varname's current value
+# or if varname is undefined
+proc ::tcl::SetMax {varname value} {
+    upvar 1 $varname var
+    if {![info exists var] || $value > $var} {
+        set var $value
+    }
+}
+
+# Set the varname to value if value is smaller than varname's current value
+# or if varname is undefined
+proc ::tcl::SetMin {varname value} {
+    upvar 1 $varname var
+    if {![info exists var] || $value < $var} {
+        set var $value
+    }
+}
+
+
+    # everything loaded fine, lets create the test proc:
+ #    OptCreateTestProc
+    # Don't need the create temp proc anymore:
+ #    rename OptCreateTestProc {}
+}