Tcl Library Source Code

Check-in [50fdc84e6c]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Import argparse version 0.4 which adds the ability to put overall options directly in the parameter definition list, a feature needed by the latest version of pipeline
Timelines: family | ancestors | descendants | both | amg-argparse
Files: files | file ages | folders
SHA3-256: 50fdc84e6c48e13e17db109331ed69f7cf5685de8a5d23b4f26ab0ab2f20e851
User & Date: andy 2019-04-15 03:44:13
Context
2019-04-17
06:45
Allow parse_args-style comments check-in: 487e9d220e user: andy tags: amg-argparse
2019-04-15
03:44
Merge amg-argparse check-in: ec05a2e2e4 user: andy tags: amg-pipeline
03:44
Import argparse version 0.4 which adds the ability to put overall options directly in the parameter definition list, a feature needed by the latest version of pipeline check-in: 50fdc84e6c user: andy tags: amg-argparse
2019-04-08
07:19
Begin adding argparse package check-in: ef01ec1300 user: andy tags: amg-argparse
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to modules/argparse/TODO.md.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- Remove `-boolean` 
  - Instead, act as if `-boolean` were always being passed to [argparse]
  - Remove `-keep` as well
  - Add an `-unset` switch to selectively change the behavior to unsetting a
    variable or omitting a dict key when the switch is not present
- Documentation
  - Instead of having a big comment, use doctools
  - Perhaps wait for the completion of the Tcllib documentation overhaul
  - Doctools will still be the standard afterwards, right?
- Help text generation
  - Parameter and switch descriptions given by per-element `-help` switch
  - Need overall `-help` switch to provide narrative description
  - May need special grouping elements to organize switches and parameters
  - Text formatting and word wrapping
- Automatic command usage error message
  - Takes the place of Tcl\_WrongNumArgs()






<
<







1
2
3
4
5
6
7


8
9
10
11
12
13
14
- Remove `-boolean` 
  - Instead, act as if `-boolean` were always being passed to [argparse]
  - Remove `-keep` as well
  - Add an `-unset` switch to selectively change the behavior to unsetting a
    variable or omitting a dict key when the switch is not present
- Documentation
  - Instead of having a big comment, use doctools


- Help text generation
  - Parameter and switch descriptions given by per-element `-help` switch
  - Need overall `-help` switch to provide narrative description
  - May need special grouping elements to organize switches and parameters
  - Text formatting and word wrapping
- Automatic command usage error message
  - Takes the place of Tcl\_WrongNumArgs()

Changes to modules/argparse/argparse.tcl.

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
29
30
31
32
33
34
35





36
37
38
39
40
41
42
...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
...
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260






261








262



























263
264
265
266
267
268
269
270
271
272





273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
#
# Feature-heavy argument parsing package
#
# Copyright (C) 2019 Andy Goth <[email protected]>
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
package require Tcl 8.6
package provide argparse 0.3

# argparse --
# Parses an argument list according to a definition list.  The result may be
# stored into caller variables or returned as a dict.
#
# The [argparse] command accepts the following switches:
#
................................................................................
# -validate DEF  Define named validation expressions to be used by elements
# -enum DEF      Define named enumeration lists to be used by elements
# --             Force next argument to be interpreted as the definition list
#
# After the above switches comes the definition list argument, then finally the
# optional argument list argument.  If the argument list is omitted, it is taken
# from the caller's args variable.





#
# Each element of the definition list is itself a list containing a unique,
# non-empty name element consisting of alphanumerics, underscores, and minus
# (not as the first character), then zero or more of the following switches:
#
# -switch        Element is a switch; conflicts with -parameter
# -parameter     Element is a parameter; conflicts with -switch
................................................................................
# enumeration name to validation expressions or enumeration lists.  The argument
# to a per-element -validate switch is a validation name or expression, and the
# argument to a per-element -enum switch is an enumeration name or list.  An
# element may not use both -validate and -enum.
#
# A validation expression is an [expr] expression parameterized on a variable
# named arg which is replaced with the argument.  If the expression evaluates to
# true, the argument is accepted.  
#
# An enumeration list is a list of possible argument values.  If the argument
# appears in the enumeration list, the argument is accepted.  Unless -exact is
# used, if the argument is a prefix of exactly one element of the enumeration
# list, the argument is replaced with the enumeration list element.
#
# Unambiguous prefixes of switch names are acceptable, unless the -exact switch
................................................................................
                return -code error -level 2\
                        "$name value \"$arg\" fails [dict get $opt validateMsg]"
            }]
        }
        return $args
    }}}

    # Process switches and locate the definition argument.
    set level 1
    set enum {}
    set validate {}
    for {set i 0} {$i < [llength $args]} {incr i} {
        if {[lindex $args $i] eq "--"} {
            # Stop after "--".
            incr i
            break
        } elseif {[catch {
            regsub {^-} [tcl::prefix match -message switch {
                -boolean -enum -equalarg -exact -inline -keep -level -long
                -mixed -normalize -pass -reciprocal -template -validate
            } [lindex $args $i]] {} switch
        }]} {






            # Stop at the first non-switch argument.








            break



























        } elseif {$switch ni {enum level pass template validate}} {
            # Process switches with no arguments.
            set $switch {}
        } elseif {$i == [llength $args] - 1} {
            return -code error "-$switch requires an argument"
        } else {
            # Process switches with arguments.
            set $switch [lindex $args [incr i]]
        }
    }






    # Forbid using -inline and -keep at the same time.
    if {[info exists inline] && [info exists keep]} {
        return -code error "-inline and -keep conflict"
    }

    # Extract the definition and args parameters from the argument list, pulling
    # from the caller's args variable if the args parameter is omitted.
    switch [expr {[llength $args] - $i}] {
    0 {
        return -code error "missing required parameter: definition"
    } 1 {
        set definition [lindex $args end]
        set argv [uplevel 1 {::set args}]
    } 2 {
        set definition [lindex $args end-1]
        set argv [lindex $args end]
    } default {
        return -code error "too many arguments"
    }}

    # Parse element definition list.
    set def {}
    set aliases {}
    set order {}
    set switches {}
    set upvars {}
    set omitted {}
    foreach elem $definition {
        # Skip inline comments.
        if {[info exists comment]} {
            unset comment
            continue
        } elseif {[llength $elem] == 1 && [lindex $elem 0] eq "#"} {
            set comment {}
            continue
        }

        # Read element definition switches.
        set opt {}
        for {set i 1} {$i < [llength $elem]} {incr i} {
            if {[set switch [regsub {^-} [tcl::prefix match {
                -alias -argument -boolean -catchall -default -enum -forbid
                -ignore -imply -keep -key -level -optional -parameter -pass
                -reciprocal -require -required -standalone -switch -upvar






|







 







>
>
>
>
>







 







|







 







|




<
<
<
<
|




|
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










>
>
>
>
>






<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








<
<
<
<
<
<
<
<
<







2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
...
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
...
244
245
246
247
248
249
250
251
252
253
254
255




256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325















326
327
328
329
330
331
332
333









334
335
336
337
338
339
340
#
# Feature-heavy argument parsing package
#
# Copyright (C) 2019 Andy Goth <[email protected]>
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
package require Tcl 8.6
package provide argparse 0.4

# argparse --
# Parses an argument list according to a definition list.  The result may be
# stored into caller variables or returned as a dict.
#
# The [argparse] command accepts the following switches:
#
................................................................................
# -validate DEF  Define named validation expressions to be used by elements
# -enum DEF      Define named enumeration lists to be used by elements
# --             Force next argument to be interpreted as the definition list
#
# After the above switches comes the definition list argument, then finally the
# optional argument list argument.  If the argument list is omitted, it is taken
# from the caller's args variable.
#
# A special syntax is provided allowing the above switches to appear within the
# definition list argument.  If an element of the definition list is a list
# whose first element is empty string, its subsequent elements are treated as
# additional overall switches to [argparse].
#
# Each element of the definition list is itself a list containing a unique,
# non-empty name element consisting of alphanumerics, underscores, and minus
# (not as the first character), then zero or more of the following switches:
#
# -switch        Element is a switch; conflicts with -parameter
# -parameter     Element is a parameter; conflicts with -switch
................................................................................
# enumeration name to validation expressions or enumeration lists.  The argument
# to a per-element -validate switch is a validation name or expression, and the
# argument to a per-element -enum switch is an enumeration name or list.  An
# element may not use both -validate and -enum.
#
# A validation expression is an [expr] expression parameterized on a variable
# named arg which is replaced with the argument.  If the expression evaluates to
# true, the argument is accepted.
#
# An enumeration list is a list of possible argument values.  If the argument
# appears in the enumeration list, the argument is accepted.  Unless -exact is
# used, if the argument is a prefix of exactly one element of the enumeration
# list, the argument is replaced with the enumeration list element.
#
# Unambiguous prefixes of switch names are acceptable, unless the -exact switch
................................................................................
                return -code error -level 2\
                        "$name value \"$arg\" fails [dict get $opt validateMsg]"
            }]
        }
        return $args
    }}}

    # Process arguments.
    set level 1
    set enum {}
    set validate {}
    for {set i 0} {$i < [llength $args]} {incr i} {




        if {[catch {
            regsub {^-} [tcl::prefix match -message switch {
                -boolean -enum -equalarg -exact -inline -keep -level -long
                -mixed -normalize -pass -reciprocal -template -validate
            } [lindex $args $i]] {} switch
        } msg]} {
            # Do not allow "--" or definition lists nested within the special
            # empty-string element containing extra overall switches.
            if {[info exists reparse]} {
                return -code error $msg
            }

            # Stop after "--" or at the first non-switch argument.
            if {[lindex $args $i] eq "--"} {
                incr i
            }

            # Extract definition and args from the argument list, pulling from
            # the caller's args variable if the args parameter is omitted.
            switch [expr {[llength $args] - $i}] {
            0 {
                break
            } 1 {
                set definition [lindex $args end]
                set argv [uplevel 1 {::set args}]
            } 2 {
                set definition [lindex $args end-1]
                set argv [lindex $args end]
            } default {
                return -code error "too many arguments"
            }}

            # Convert any definition list elements named empty string to instead
            # be overall switches, and arrange to reparse those switches.  Also,
            # remove inline comments from the definition list.
            set args {}
            set reparse {}
            set i -1
            foreach elem $definition[set definition {}] {
                if {$elem eq "#"} {
                    set comment {}
                } elseif {[info exists comment]} {
                    unset comment
                } elseif {[lindex $elem 0] eq {}} {
                    lappend args {*}[lrange $elem 1 end]
                } else {
                    lappend definition $elem
                }
            }
        } elseif {$switch ni {enum level pass template validate}} {
            # Process switches with no arguments.
            set $switch {}
        } elseif {$i == [llength $args] - 1} {
            return -code error "-$switch requires an argument"
        } else {
            # Process switches with arguments.
            set $switch [lindex $args [incr i]]
        }
    }

    # Fail if no definition argument was supplied.
    if {![info exists definition]} {
        return -code error "missing required parameter: definition"
    }

    # Forbid using -inline and -keep at the same time.
    if {[info exists inline] && [info exists keep]} {
        return -code error "-inline and -keep conflict"
    }
















    # Parse element definition list.
    set def {}
    set aliases {}
    set order {}
    set switches {}
    set upvars {}
    set omitted {}
    foreach elem $definition {









        # Read element definition switches.
        set opt {}
        for {set i 1} {$i < [llength $elem]} {incr i} {
            if {[set switch [regsub {^-} [tcl::prefix match {
                -alias -argument -boolean -catchall -default -enum -forbid
                -ignore -imply -keep -key -level -optional -parameter -pass
                -reciprocal -require -required -standalone -switch -upvar

Changes to modules/argparse/pkgIndex.tcl.

1
package ifneeded argparse 0.3 [list source [file join $dir argparse.tcl]]
|
1
package ifneeded argparse 0.4 [list source [file join $dir argparse.tcl]]