How to make an optional argument in tcl?
i.e. "puts" has an optional argument -nonewline, which
do not have to be there.
puts -nonewline "help optional argument"
and it has syntax like "puts ?-nonewline? string"
Thank you,
Tim
I'm sure you'll get contrary opinions but I'm fond of OptProc:
::tcl::OptProc someProc {
{anArg "The first argument"}
{another "The second argument"}
{-aswitch "$aswitch is 0 by default, 1 if -aswitch is specified."}
{-anOption -choice {foo bar baz} "$anOption will be foo, bar, or
baz"}
} {
...body, as for proc
}
OptProc is slow but very flexible and natural.
I once wrote a man page for this. I don't know if it ever made the
distribution.
Chris
--
The reasonable man adapts himself to the world; the unreasonable one
persists in trying to adapt the world to himself. Therefore all
progress depends on the unreasonable man. -- George Bernard Shaw
> Hi,
>
> How to make an optional argument in tcl?
args
> i.e. "puts" has an optional argument -nonewline, which
> do not have to be there.
>
> puts -nonewline "help optional argument"
>
> and it has syntax like "puts ?-nonewline? string"
proc puts args {
foreach {a b c} $args break
switch [llength $args] {
1 {
set nonewline 0
set channel stdout
set text $a
}
2 {
if {[string equal $a -nonewline]} {
set nonewline 1
set channel stdout
} else {
set nonewline 0
set channel $a
}
set text $b
}
3 {
if {[string equal $a -nonewline]} {
set nonewline 1
set channel $b
} elseif {[string equal $b -nonewline]} {
set nonewline 1
set channel $a
} else {
error {puts ?-nonewline? ?channel? text}
}
set text $c
}
default {
error {puts ?-nonewline? ?channel? text}
}
}
internal::putsline $nonewline $channel $text
}
You can use the "args" special keyword, which basically gets all the
remaining arguments, e.g.
proc foo {bar args} {
puts "Bar is: $bar , rest: $args"
}
foo something some more arguments
You can use this, to then parse optional arguments:
proc puts {args} {
foreach item $args {
switch $item {
"-nonewline" { # do something }
}
}
}
This is the general idea. I believe there is a package somewhere which
can take care of all this for you.
proc example1 {arg1 {arg2 {}}} {
puts "Mandatory argument is $arg1"
if {[string equal $arg2 {}]} {
puts "Optional argument absent"
} else {
puts "Optional argument is $arg2"
}
}
Unfortunately, one can't put optional arguments before mandatory ones
with this mechanism, so the "puts ?-nonewline? string" syntax can't be
replicated this way. For the general case, it's necessary to use the
"args" mechanism for variable numbers of arguments:
proc example2 {args} {
switch [llength $args] {
1 {
set arg2 [lindex $args 0]
puts "Mandatory argument is $arg2"
puts "Optional argument absent"
}
2 {
set arg1 [lindex $args 0]
set arg2 [lindex $args 1]
puts "Mandatory argument is $arg2"
puts "Optional argument is $arg1"
}
default {
error {wrong # args: should be "example2 ?arg1? arg2"}
}
}
# Do something with the arguments here...
}
This is verbose and can get repetitive to code, so many people have
written helper procs to simplify the task. Some of these are enumerated
on the wiki at <URL:http://mini.net/tcl/1730.html >
Stephen
--
Stephen Trier
Technical Development Lab
Cleveland FES Center
s...@po.cwru.edu
> How to make an optional argument in tcl?
Lately, I have started using the cmdline package from tcllib. I learned
this trick after reading some code from the fine http package and IIRC the
ftp package. All mistakes are my own. Here is an example of how to make
your command-line program take optional arguments. This can be very easily
changed to allow procedures to take optional arguments. For details on
that, I recommend visiting the tcllib source.
;#####################################################################
;# First, make a usage proc that you call when the user needs help.
;# Usage returns zero.
;# Do NOT call this if there was an error parsing options.
proc usage {} {
global argv0
puts "Usage: $argv0 \[OPTION VALUE\]... \[FILE\]"
puts "Does something with the FILE."
puts "OPTION TYPE DESCRIPTION"
puts "------ ----- -----------"
puts "-show bool If it should output something to stdout."
puts " Defaults to true."
puts "-db bool If it should use the database."
puts " Defaults to false."
exit
}
;# Be friendly to the user; be aware of traditional help flags.
if {[string equal $argv ""] || [string equal $argv "-?"] || \
[string equal $argv "--help"] || [string equal $argv "-help"]} {
usage
}
;# Now parse the arguments to the program, using the cmdline package.
;# Option processing: start with the defaults, then run through the
;# list of arguments.
;# See the usage proc for details on option defaults.
set show 1
set db 0
while {[set err [getopt argv {show.arg db.arg} opt arg]]} {
if {$err < 0} {
puts "$argv0 : $arg"
exit -1
}
switch -exact -- $opt {
show -
db {
if {![string is boolean $arg]} {
puts "$argv0 : Argument to -$opt has to be boolean"
exit -1
}
set $opt $arg
}
default {;# Can't happen}
}
}
;# The arguments that are mandatory are now checked, and set.
if {[llength $argv] != 1} {
puts "$argv0 : Illegal number of arguments, expected one"
exit -1
}
set file [lindex $argv 0]
;#####################################################################
--
Rennor Thomson
rennor.thomson*at*gmx.net
> This is verbose and can get repetitive to code, so many people have
> written helper procs to simplify the task. Some of these are enumerated
> on the wiki at <URL:http://mini.net/tcl/1730.html >
I agree that this is repetitive and verbose, especially my version in a
different post in this thread. I have often wondered if using a graphical
tool (written in Tk of course) would help so that you could generate at
least this piece of boilerplate. It would allow you to fill in the optional
arguments and their types into entry boxes, as well as the usage and would
generate error-checking code for procedures and command line tools.
I think a folding editor might help as well since you could fold away the
error checking code. "Out of sight, out of mind." I have heard of
experienced Java programmers complaining that javadoc makes their code messy
and hard to read. I find this as well with option processing.
Any suggestions are welcomed.
--
Rennor Thomson
rennor.thomson*at*gmx.net
Chris, I don't see it in the current tcl 8.4 framework; perhaps it
could be submitted to tcl.sf.net as a feature request.
--
"I know of vanishingly few people ... who choose to use ksh." "I'm a minority!"
<URL: mailto:lvi...@cas.org> <URL: http://www.purl.org/NET/lvirden/>
Even if explicitly stated to the contrary, nothing in this posting
should be construed as representing my employer's opinions.
Juan Carlos---
> Thank you,
> Tim
I've long been using a rather simplistic method for optional
proc args. It only works for trailing options, and only those with
values (ie. doesn't work for puts -nonewline), but if you can
live with that it has the advantage of using no external packages,
is efficient and extremely simple.
proc Myproc {v1 v2 args} {
array set p {-nonewline 0}
array set p $args
if {$p(-nonewline)} {
...
}
}
One drawback to this definition is that it isn't easily transitive to
sub proc calls. So normally I define it this way instead:
proc Myproc {v1 v2 {arg {}}} {
--
Peter MacDonald BrowseX Systems Inc
Email: pe...@BrowseX.com http://BrowseX.com
Phone: (250) 595-5998