Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

URGENT: Command argument parsing

9 views
Skip to first unread message

physio...@gmail.com

unread,
Apr 12, 2007, 10:42:22 AM4/12/07
to
Hi,

I am searching for a command argument parsing package which can
provide following feature

1.) Dependency/order in arguments
2.) Multiple count of an argument

For example,

abc -x foo1 -y bar1 -z sha1 -x foo2 -x foo3 -y bar3 -z sha2

So, here the count of argument '-x' and the sequence/dependency of '-
x', '-y', '-z' is important.

Regards,
-Madhur

Neil Madden

unread,
Apr 12, 2007, 11:26:49 AM4/12/07
to

What would you want the result of this argument parsing to look like?
Quite possibly [lsearch] provides most of what you want, particularly
with the -all option, e.g.:

% set ops {-x foo1 -y bar1 -z sha1 -x foo2 -x foo3 -y bar3 -z sha2}
% lsearch -all $ops -x
0 6 8

-- Neil

Bryan Oakley

unread,
Apr 12, 2007, 12:26:50 PM4/12/07
to

Your requirements are a big vague. For example, do you want this package
to execute code or simply parse the arguments into some structure you'll
traverse later? Can the arguments be abbreviated? Can some be omitted?

Those questions might all be rhetorical. IMO you don't really need a
package to do many kinds of argument parsing, it's quite easy to write
your own argument processing and you won't be tied to limitations of
whatever package you use.

set lastOption ""
while {[string match "-*" [lindex $args 0]]} {
set option [lindex $args 0]
set args [lrange $args 1 end]
switch -exact -- $option {
-- {break}
-x {
set value [lindex $args 0]
set args [lrange $args 1 end]
<other code to handle -x>
set lastOption "-x"
}
-y {
if {$lastOption != "-x"} {
<throw error>
}
set value [lindex $args 1]
set args [lrange $args 1 end]
<other code to handle -y>
set lastOption "-y"
}
-z {
... and so on
}
}
}

The above is, of course, just one of many possible ways to parse the
arguments. Parsing lists of stuff is something Tcl is naturally good at.

--
Bryan Oakley
http://www.tclscripting.com

Cameron Laird

unread,
Apr 12, 2007, 12:10:29 PM4/12/07
to
In article <1176388942.5...@w1g2000hsg.googlegroups.com>,
.
.
.
I'm sure some of the solutions in <URL: http://wiki.tcl.tk/1730 >
offer these. I don't know which.

sleb...@gmail.com

unread,
Apr 12, 2007, 11:14:48 PM4/12/07
to

If your arguments are always in the form of "-option value ..." then
the best, easiest to read and maintain, solution is the simplest:

foreach {op val} $args {
switch -- $op {
-x {#do something to $val}
-y {#do something to $val}
-z {#do something to $val}
}
}

If your requirement is more complex than that, for example if you need
to do stuff like:

abc -x foo1 -y bar1 -sha1 -x foo2 -x foo3 foo4 -y bar3 -sha2

Then my favourite method is: http://wiki.tcl.tk/16032
Essentially, once you've defined the Perl-like [shift] and [unshift]
functions you can pretty much do anything:

while {[llength $args] > 0} {
set op [shift args]
switch -- $op {
-x {
set val [list]
while 1 {
set x [shift args]
# stop at first sign of new option:
if {[regexp -- {-.*} $x]} {
unshift args $x
break
}
lappend val $x
}
# do something to val list
}
-y {
set val [shift args]
# do something to val
}
-sha1 {#do something}
-sha2 {#do something}
}
}

mark anthony

unread,
Apr 13, 2007, 4:15:44 AM4/13/07
to
On Apr 13, 5:14 am, "slebet...@yahoo.com" <slebet...@gmail.com> wrote:
> On Apr 12, 10:42 pm, physiologo...@gmail.com wrote:
> > 1.) Dependency/order in arguments
> > 2.) Multiple count of an argument
> If your arguments are always in the form of "-option value ..." then
> the best, easiest to read and maintain, solution is the simplest:

if my arguments are in the form of "-option value ..." and i'm lazy
i create an array lookup

::array set options {
-option1 varName1
-option1 varName2
}

## here you could check that llength is even

::foreach [::list option value] $args {
::if {![::info exists options($option)]} then {
::continue
## or through error
}
::set $options($option) $value
}


This works fine for the simplest form, but does not do
what Madhur requested.

one might add more code for handling like

$options($option,handle) $options($option,varname) $value

instead of

::set $options($option) $value

BUT if the order of -x -y -z is important and there are
multiple instances, and they belong together, why not
pass them as one option???

::proc coord { x y z } { ::return [::list $x $y $z] }

## abc -x foo1 -y bar1 -z sha1 -x foo3 -y bar3 -z sha2

abc [coord foo1 bar1 sha1 ] [coord foo3 bar3 sha2]

but more details on what -x -y -z do, would have been
more helpful.

cheers,
mark


Glenn Jackman

unread,
Apr 13, 2007, 11:49:23 AM4/13/07
to
At 2007-04-13 04:15AM, "mark anthony" wrote:
> On Apr 13, 5:14 am, "slebet...@yahoo.com" <slebet...@gmail.com> wrote:
> > If your arguments are always in the form of "-option value ..." then
> > the best, easiest to read and maintain, solution is the simplest:
>
> if my arguments are in the form of "-option value ..." and i'm lazy
> i create an array lookup
>
> ::array set options {
> -option1 varName1
> -option1 varName2
> }

But then you lose the ability to have multiple uses of -option (despite
your typo above).

--
Glenn Jackman
"You can only be young once. But you can always be immature." -- Dave Barry

physio...@gmail.com

unread,
Apr 13, 2007, 4:24:25 PM4/13/07
to
Hi Neil,

My end goal is to have it as a generic parser as it will be used by
many programs. So, it seems quite a lot of work to duplicate for each
of the program separately.

lsearch should help to implement this one. Two things,

firstly there is no restriction of how many values a particular
argument will have. I would prefer not to put any restriction of
providing comma or any other delimiter separated list. Whitespace
seems natural.

for example -z can take many options sha1 sha2 ... and so on.

Also, -y has no meaning without -x and -z has no meaning without -y
and -x. This relation would be a bit tough to check with lsearch.

I guess there is no such package available. I clearly remember using
such command line argument scheme in some standard unix program(s).

Regards,
-Madhur

physio...@gmail.com

unread,
Apr 13, 2007, 4:35:51 PM4/13/07
to
Hi Bryan,

I need the code to parse the arguments and return them into a
structure. Preferably an array. Abbreviating arguments is not
necessary for me. Thats more of a cosmetic requirement for me.
Omitted? I am confused as to what you mean by that. It is definitely
possible that a particular -x may not have -y and hence -z. But for
ever -y only one single -x should be there and for every -z one single
-y should be there.

Basically my requirement is that I need a list of options which are
nested further depending upon needs.

{-x xyz [-y abc [-z <can_be_a_space_separated_list>]]}

I am looking for a package or a procedure/API because it will be used
with many programs which are supposed to have similar command line
argument style.

Duplicating the code for every program sounds cumbersome. One bigger
thing is how to contruct an input/output structure for such procedure/
API. I was hoping that some standard package could help me save some
time in writing and testing the code.

Regards,
-Nadhur

physio...@gmail.com

unread,
Apr 13, 2007, 4:45:31 PM4/13/07
to
Hi Mark,

You suggested quite a good solution. But the requirement is to parse
nested lists of lists of arguments. To illustrate my need for optional
and dependent list of lists as arguments is shown below.

-x {a b c} -y {{j k} {l} {m n}} -z {{{d e} {d e}} {{p q}} {{i} {i}}}

Here -x drives the requirement for -y and hence -z. The options "a b
c" have further many -y options and each -y would further have many
options further. I felt that a command line user interface could be
more friendly if done in the way I proposed as compared to the one I
have written in the example as a cluttered lists of lists.

I remember using such command line arguments in standard unix
programs. But I cannot remember which ones. A TCL package/API is must
because I would be using it for several 10s of programs which are
supposed to have similar look and feel as being part of a software.
Any help about such an existing package would be really helpful. I
have very less time to implement such an API myself.

Regards,
-Madhur

Glenn Jackman

unread,
Apr 13, 2007, 5:07:30 PM4/13/07
to
At 2007-04-13 04:24PM, "physio...@gmail.com" wrote:
> Hi Neil,
>
> My end goal is to have it as a generic parser as it will be used by
> many programs. So, it seems quite a lot of work to duplicate for each
> of the program separately.
>
> lsearch should help to implement this one. Two things,
>
> firstly there is no restriction of how many values a particular
> argument will have. I would prefer not to put any restriction of
> providing comma or any other delimiter separated list. Whitespace
> seems natural.
>
> for example -z can take many options sha1 sha2 ... and so on.
>
> Also, -y has no meaning without -x and -z has no meaning without -y
> and -x. This relation would be a bit tough to check with lsearch.
>
> I guess there is no such package available. I clearly remember using
> such command line argument scheme in some standard unix program(s).

The usage you describe goes above what "standard" unix command line
parsing (i.e. getopts in bash) gives you. These option dependenancies
are certainly something you have to program for yourself.

Tcl does have a few command line packages. In tcllib, you'll find
cmdline (http://tcllib.sourceforge.net/doc/cmdline.html).

The cmdline::getoptions proc cannot handle multiple instances of
options:

package require cmdline
set options {
{x.arg "" "-x argument"}
{y.arg "" "-y argument"}
{z.arg "" "-z argument"}
}
set args [list -x X1 -y Y1 -x X2 -x X3 -y Y2 -z Z1 -x X4]
array set parms [cmdline::getoptions args $options]
parray parms
# parms(x) = X4
# parms(y) = Y2
# parms(z) = Z1

However, the cmdline::getopt can, but you still have to code your
dependancies inside the while loop.

package require cmdline
set options {x.arg y.arg z.arg}
set args [list -x X1 -y Y1 -x X2 -x X3 -y Y2 -z Z1 -x X4]

while {[set status [cmdline::getopt args $options opt val]] > 0} {
puts "have -$opt = $val"
}
if {$status < 0} {
error $val
}

You can look on the tcl wiki for other argument processing attempts:
http://wiki.tcl.tk/references/5883!

sleb...@gmail.com

unread,
Apr 13, 2007, 7:48:08 PM4/13/07
to
On Apr 14, 4:45 am, physiologo...@gmail.com wrote:
> Hi Mark,
>
> You suggested quite a good solution. But the requirement is to parse
> nested lists of lists of arguments. To illustrate my need for optional
> and dependent list of lists as arguments is shown below.
>
> -x {a b c} -y {{j k} {l} {m n}} -z {{{d e} {d e}} {{p q}} {{i} {i}}}
>
> Here -x drives the requirement for -y and hence -z. The options "a b
> c" have further many -y options and each -y would further have many
> options further. I felt that a command line user interface could be
> more friendly if done in the way I proposed as compared to the one I
> have written in the example as a cluttered lists of lists.
>

For such a requirement I find that it's easier to read and maintain an
internal structure like:

{
x
{x y}
{x {y z}}
}

or

{
{x {}}
{x {y {}}}
{x {y z}}
}

Basically, each item is: [list $x [list $y $z]]

Thereby each x is directly linked to it's y and each y is directly
linked to it's z without having to depend on position calculations in
3 separate lists. So your original example should parse to become:

{foo1 {bar1 sha1}} {foo3 {bar3 sha2}}

> I remember using such command line arguments in standard unix
> programs. But I cannot remember which ones. A TCL package/API is must
> because I would be using it for several 10s of programs which are
> supposed to have similar look and feel as being part of a software.
> Any help about such an existing package would be really helpful. I
> have very less time to implement such an API myself.
>

Even if you have to write a custom parser you can still write it as a
package thereby avoiding code duplication. Here's one possible
implementation written as a package. Simply save it as a file called
parsexyz.tcl and save it in parsexyz/parsexyz.tcl and run the command
[pkg_mkIndex parsexyz parsexyz/parsexyz.tcl] to generate the index
file:

# Simple implementation, no validation done on values:
proc parseXYZ {arglist} {
set ret [list]
while {[llength $arglist]} {
set op [shift arglist]
if {"-x" == $op} {
set x [shift arglist]
set op [shift arglist]
if {"-y" == $op} {
set y [shift arglist]
set op [shift arglist]
if {"-z" == $op} {
set z [shift arglist]
lappend ret [list $x [list $y $z]]
} else {
unshift arglist $op
lappend ret [list $x $y]
}
} else {
unshift arglist $op
lappend ret $x
}
} else {
error "unexpected argument: $op"
}
}
}

proc shift {ls} {
upvar 1 $ls LIST
if {[llength $LIST]} {
set ret [lindex $LIST 0]
set LIST [lreplace $LIST 0 0]
return $ret
} else {
error "Ran out of list elements."
}
}

proc unshift {ls data} {
upvar 1 $ls LIST
set LIST [concat $data $LIST]
}

package provide parsexyz 1.0

sleb...@gmail.com

unread,
Apr 13, 2007, 7:53:17 PM4/13/07
to
On Apr 14, 7:48 am, "slebet...@yahoo.com" <slebet...@gmail.com> wrote:
> proc parseXYZ {arglist} {
> set ret [list]
> while {[llength $arglist]} {
> set op [shift arglist]
> if {"-x" == $op} {
> set x [shift arglist]
> set op [shift arglist]
> if {"-y" == $op} {
> set y [shift arglist]
> set op [shift arglist]
> if {"-z" == $op} {
> set z [shift arglist]
> lappend ret [list $x [list $y $z]]
> } else {
> unshift arglist $op
> lappend ret [list $x $y]
> }
> } else {
> unshift arglist $op
> lappend ret $x
> }
> } else {
> error "unexpected argument: $op"
> }
> }
> }

Crap that should have been:

proc parseXYZ {arglist} {
set ret [list]
while {[llength $arglist]} {
set op [shift arglist]
if {"-x" == $op} {
set x [shift arglist]
set op [shift arglist]
if {"-y" == $op} {
set y [shift arglist]
set op [shift arglist]
if {"-z" == $op} {
set z [shift arglist]
lappend ret [list $x [list $y $z]]
} else {
unshift arglist $op
lappend ret [list $x $y]
}
} else {
unshift arglist $op
lappend ret $x
}
} else {
error "unexpected argument: $op"
}
}

return $ret; ### Forgot to return the result!!
}

M. Strobel

unread,
Apr 21, 2007, 8:04:27 AM4/21/07
to
physio...@gmail.com schrieb:

Hi,

I just discovered an undocumented package in my TCL installation
(opensuse 10.2) - see this terminal protocol:


strobel@lx007:~/tcl> tclsh
% package require opt
0.4.4.1
%

The code is located on my system in /usr/share/tcl/tcl8.4/opt0.4 and is
roughly 1000 lines.

It should offer some features, but I didn't analyze it yet.

Max

Donal K. Fellows

unread,
Apr 22, 2007, 6:43:06 AM4/22/07
to
M. Strobel wrote:
> I just discovered an undocumented package in my TCL installation
> (opensuse 10.2) - see this terminal protocol:
[...]

> The code is located on my system in /usr/share/tcl/tcl8.4/opt0.4 and is
> roughly 1000 lines.
>
> It should offer some features, but I didn't analyze it yet.

The opt package is part of Tcl, but is (apparently) unsupported. It's
quality is unclear. (Yeah, we ought to decide whether it is actually
supported and, if so, add tests and documentation.)

Donal.

Donal K. Fellows

unread,
Apr 22, 2007, 6:46:12 AM4/22/07
to
Donal K. Fellows wrote:
> The opt package is part of Tcl, but is (apparently) unsupported. It's
> quality is unclear. (Yeah, we ought to decide whether it is actually
> supported and, if so, add tests and documentation.)

Correction: it's got tests. Still ought to be documented.

Donal.

0 new messages