Author: jisom
Date: Wed Jan 11 14:12:39 2006
New Revision: 11104
Added:
trunk/runtime/parrot/library/Getopt/Obj.pir (contents, props changed)
trunk/t/library/getopt_obj.t (contents, props changed)
Modified:
trunk/MANIFEST
Log:
Add runtime/parrot/library/Getopt/Obj.pir and it's test.
Modified: trunk/MANIFEST
==============================================================================
--- trunk/MANIFEST (original)
+++ trunk/MANIFEST Wed Jan 11 14:12:39 2006
@@ -1503,6 +1503,7 @@ runtime/parrot/library/File/Spec.pir
runtime/parrot/library/File/Spec/Unix.pir [library]
runtime/parrot/library/File/Spec/Win32.pir [library]
runtime/parrot/library/Getopt/Long.pir [library]
+runtime/parrot/library/Getopt/Obj.pir [library]
runtime/parrot/library/JSON.pir [library]
runtime/parrot/library/JSON/Parser.pir [library]
runtime/parrot/library/PGE/Dumper.pir [library]
@@ -1904,6 +1905,7 @@ t/library/File-Spec.t
t/library/data_escape.t []
t/library/dumper.t []
t/library/getopt_long.t []
+t/library/getopt_obj.t []
t/library/json.t []
t/library/md5.t []
t/library/parrotlib.t []
Added: trunk/runtime/parrot/library/Getopt/Obj.pir
==============================================================================
--- (empty file)
+++ trunk/runtime/parrot/library/Getopt/Obj.pir Wed Jan 11 14:12:39 2006
@@ -0,0 +1,778 @@
+=head1 NAME
+
+library/Getopt/Obj.pir - parse long and short command line options
+
+=head1 SYNOPSIS
+
+ .sub main :main
+ .param pmc argv
+ .local string prog_name
+ prog_name = shift argv
+ load_bytecode "Getopt/Obj.pir"
+ .local pmc getopts
+ getopts = new "Getopt::Obj"
+ getopts."notOptStop"(1)
+
+ $P0 = getopts."add"()
+ $P0."name"("FooBar")
+ $P0."long"("foo")
+ $P0."short"("f")
+ $P0."optarg"(1)
+ $P0."type"(.String)
+
+ .local pmc opts
+ opts = getopts."get_options"(argv)
+ .local string foo
+ foo = opts["Foobar"]
+ .end
+
+=head1 DESCRIPTION
+
+This library parses options from the command line. Options may take
+and of these forms, currently:
+
+ --foo=bar Set foo to bar
+ -f bar Set f to bar (with conditions)
+ -fthis=that If f is a Hash, set key 'this' to 'that'
+ -f Set f (if it's Boolean or has an optional argument)
+ -fbar Set f to bar if it's not a Boolean
+ -abc If -a -b and -c are all Booleans, set them all
+ --foo=this=that If foo is a Hash, set key 'this' to 'that'
+ Both equal signs are required
+ -- Stop processing args, -- is removed from argv
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item C<__load()>
+
+States that Getopt::Obj and Getopt::Obj::Spec are classes to use and defines
+the attributes they'll use.
+
+=cut
+
+.sub __load :anon :load
+ .local pmc obj, spec
+ obj = newclass "Getopt::Obj"
+ addattribute obj, "Specs"
+ addattribute obj, "notOptStop"
+
+ spec = newclass "Getopt::Obj::Spec"
+ addattribute spec, "name"
+ addattribute spec, "long"
+ addattribute spec, "short"
+ addattribute spec, "type"
+ addattribute spec, "optarg"
+.end
+
+.include "library/dumper.pir"
+.include "iterator.pasm"
+
+=back
+
+=head2 Class Getopt::Obj
+
+Our nice little module.
+
+=over 4
+
+=cut
+
+.namespace ["Getopt::Obj"]
+
+=item C<__init()>
+
+Creates the Specs and notOptStop attribute, interal stuff.
+
+=cut
+
+.sub __init :method
+ $P0 = new .ResizablePMCArray
+ setattribute self, "Specs", $P0
+ $P0 = new .Boolean
+ setattribute self, "notOptStop", $P0
+.end
+
+=item C<HASH get_options(ARRAY ARGV)>
+
+Parses ARGV, modifying it inplace, and returns a hash with the keys and values
+wanted.
+
+=cut
+
+.sub get_options :method
+ .param pmc argv
+ # This is necessary to get access to some vtable methods
+ makeResizable(argv)
+ .local pmc return, spec
+ .local int i, j, argc
+ .local string name, long, short, arg, key, val
+ return = new .Hash
+
+ push_eh handler
+ i = 0
+beginfor:
+ argc = argv
+ key = ''
+ val = ''
+ name = ''
+ unless i < argc goto endfor
+ arg = argv[i]
+ if arg == '-' goto redofor # lonesome dash
+ unless arg == '--' goto endif_0 # no more args, done
+ delete argv[i]
+ goto endfor
+endif_0:
+ $S0 = substr arg, 0, 1
+ unless $S0 != '-' goto endif_1
+ # This will work for if the option does not start with a hyphen
+ $I0 = self."notOptStop"()
+ if $I0 goto endfor
+ goto redofor # not an arg for us, next!
+endif_1:
+
+ # ok now, we know we've got an arg to process, maybe long
+ # maybe short, maybe with it's own argument.
+ $S0 = substr arg, 0, 2
+ unless $S0 == '--' goto shortarg
+
+ ################ LONG ############################
+
+ # TODO type and optarg not checked
+ $I0 = index arg, '='
+ if $I0 == -1 goto else_2
+ $I0 -= 2
+ key = substr arg, 2, $I0
+ $I0 += 3
+ val = substr arg, $I0
+ # XXX use this or not?
+ # return undef for --foo=
+ $I0 = length val
+ if $I0 goto endif_3
+ null val
+endif_3:
+ goto endif_2
+else_2:
+ # most likely a boolean
+ key = substr arg, 2
+ null val
+endif_2:
+ (name, spec) = self."getNameForKey"(key)
+ long = spec."long"()
+ $I0 = length $S0
+ unless long == key goto beginstore
+ $I0 = spec."optarg"()
+ $I1 = spec."type"()
+ unless $I1 == .Boolean goto endif_4
+ val = 1
+ goto beginstore
+endif_4:
+ if $I0 goto beginstore
+ if_null val, error_0
+ goto beginstore
+error_0:
+ MissingRequired(long)
+
+ ################ SHORT ###########################
+
+shortarg:
+ # get the first char
+ key = substr arg, 1, 1
+ # and the others...
+ val = substr arg, 2
+
+ (name, spec) = self."getNameForKey"(key)
+ key = name
+
+ $I1 = spec."type"()
+ $I2 = length val
+ unless $I1 == .Boolean goto else_6
+ if $I2 == 0 goto beginstore
+ # ok, boolean and bundled
+ .local string keys
+ keys = substr arg, 1
+ .local int jkl, mno
+ jkl = 0
+ mno = length keys
+beginfor_0:
+ unless jkl < mno goto endfor_0
+ key = substr keys, jkl, 1
+
+ (name, spec) = self."getNameForKey"(key)
+ $I0 = spec."type"()
+ unless $I0 == .Boolean goto error_2
+
+ $P0 = new .Boolean
+ $P0 = 1
+ return[name] = $P0
+ inc jkl
+ goto beginfor_0
+endfor_0:
+
+ # this should probably a next, I think, maybe, it works, so maybe not.
+ goto beginstore
+else_6:
+ # Not a boolean...
+ # If a -Ifoo type...
+ if $I2 != 0 goto beginstore
+ # just a -f type, do the optarg check here
+ $I0 = spec."optarg"()
+ if $I0 goto beginstore
+ delete argv[i]
+ argc = argv
+ unless i < argc goto error_1
+ # XXX/TODO doesn't yet check the value of argv[i]
+ # to see if it's a possible argument
+ # argv[i] gets deleted before going to the next arg
+ val = argv[i]
+ goto beginstore
+error_1:
+ MissingRequired(name)
+error_2:
+ $P0 = new .Exception
+ $P0["_message"] = "Not using only boolean arguments in a bundled argument"
+ throw $P0
+
+ ################ STORE ###########################
+
+beginstore:
+ (name, spec) = self."getNameForKey"(key)
+ # Store the value...
+ $I0 = spec."type"()
+ $S0 = typeof $I0
+ if_null val, undef
+ if $I0 == .String goto str
+ if $I0 == .Array goto array
+ if $I0 == .Hash goto hash
+ if $I0 == .Integer goto integer
+ if $I0 == .Float goto flt
+ if $I0 == .Boolean goto bool
+ # XXX default to boolean?
+ # And are pmc's necessary?
+ goto bool
+undef:
+ $I0 = spec."optarg"()
+ unless $I0 goto optelse
+ $P0 = new .Undef
+ goto endifelse
+optelse:
+ MissingRequired(name)
+ goto endifelse
+array:
+ $P0 = return[name]
+ $I0 = typeof $P0
+ unless $I0 != .ResizablePMCArray goto endif_5
+ $P0 = new .ResizablePMCArray
+endif_5:
+ push $P0, val
+ goto endifelse
+hash:
+ $P0 = return[name]
+ $I0 = typeof $P0
+ unless $I0 != .Hash goto endif_7
+ $P0 = new .Hash
+endif_7:
+ $I0 = index val, '='
+ unless $I0 == -1 goto else_8
+ $P0[val] = 1
+ goto endifelse
+else_8:
+ $S0 = substr val, 0, $I0
+ inc $I0
+ $S1 = substr val, $I0
+ $P0[$S0] = $S1
+ goto endifelse
+str:
+ $P0 = new .String
+ $P0 = val
+ goto endifelse
+integer:
+ $P0 = new .Integer
+ $I0 = val
+ $P0 = $I0
+ goto endifelse
+flt:
+ $P0 = new .Float
+ $N0 = val
+ $P0 = $N0
+ goto endifelse
+bool:
+ $P0 = new .Boolean
+ $P0 = 1
+endifelse:
+ return[name] = $P0
+
+nextfor:
+ delete argv[i]
+ goto beginfor
+redofor:
+ inc i
+ goto beginfor
+endfor:
+
+ goto finish
+handler:
+ get_results "(0,0)", $P0, $S0
+ if $S0 == "Option key not found" goto endif_6
+ rethrow $P0
+endif_6:
+ $I0 = self."notOptStop"()
+ if $I0 goto finish
+ # This seems necessary...don't know why
+ push_eh handler
+ inc i
+ goto beginfor
+
+finish:
+ clear_eh
+ .return(return)
+.end
+
+=item C<makeResizable(PMC argv)>
+
+Converts the given array into a ResizablePMCArray... Morph won't morph it
+and some of the things we do to it need certain vtable methods available.
+
+=cut
+
+.sub makeResizable
+ .param pmc argv
+ .local pmc argnew
+ .local int k, argc
+ argnew = new .ResizablePMCArray
+ k = 0
+ argc = argv
+beginfor:
+ unless k < argc goto endfor
+ $P0 = shift argv
+ push argnew, $P0
+ inc k
+ goto beginfor
+endfor:
+ assign argv, argnew
+.end
+
+=item C<Getopt::Obj::Spec add()>
+
+Adds a new option to the parsing. You don't need to know what class it is
+(internal data), just that you get an object to invoke methods on.
+
+=cut
+
+.sub "add" :method
+ .local pmc spec, specs
+ spec = new "Getopt::Obj::Spec"
+ specs = getattribute self, "Specs"
+ push specs, spec
+ .return(spec)
+.end
+
+=item C<STRING getNameForKey(STRING key)>
+
+Given a key, maybe long or short, or when storing, the name itself perhaps,
+return the name for the key.
+
+=cut
+
+# XXX should the name really ever be passed?
+
+.sub "getNameForKey" :method
+ .param string key
+ .local int j, specslen
+ .local pmc specs, spec
+ .local string name, long, short
+ specs = getattribute self, "Specs"
+ specslen = specs
+ j = 0
+beginfor:
+ unless j < specslen goto endfor
+ spec = specs[j]
+ name = spec."name"()
+ if key == name goto return
+ long = spec."long"()
+ if key == long goto return
+ short = spec."short"()
+ if key == short goto return
+ goto nextfor
+return:
+ .return(name, spec)
+ goto endfor
+nextfor:
+ inc j
+ goto beginfor
+endfor:
+ # Don't return anything, easier to catch an exception...
+ $P0 = new .Exception
+ $P0["_message"] = "Option key not found"
+ throw $P0
+.end
+
+=item C<INT self."notOptStop"()>
+
+=item C<INT self."notOptStop"(INT val)>
+
+Boolean method, so setting it to 2 is no different than setting it to 1. If
+notOptStop is set to a true value, then get_options will stop after it reaches
+an argument not specified by the program. This is either an unrecognized
+option, such as a mistyped argument, or an argument means to be passed on again
+later. Or of course, it's not an argument at all and perhaps a filename.
+
+=cut
+
+.sub "notOptStop" :method
+ .param int val :optional
+ .param int opt :opt_flag
+ unless opt goto else_0
+ # Setting
+ $P0 = new .Boolean
+ $P0 = val
+ setattribute self, "notOptStop", $P0
+ goto endif_0
+else_0:
+ # Getting
+ $P0 = getattribute self, "notOptStop"
+ val = $P0
+endif_0:
+ .return(val)
+.end
+
+=item C<MissingRequired(STRING arg)>
+
+When a required argument is missing, throws an exception with the message
+"Missing a required argument".
+
+=cut
+
+.sub MissingRequired
+ .param string arg
+ #printerr "Missing a required argument to "
+ #printerr arg
+ #printerr "\n"
+ #exit 1
+ $P0 = new .Exception
+ $P0["_message"] = "Missing a required argument"
+ throw $P0
+.end
+
+=back
+
+=head2 Class Getopt::Obj::Spec
+
+Interal use only, at least don't do any new "Getopt::Obj::Spec" yourself...
+This makes an easy holder for each possible match.
+
+=over 4
+
+=cut
+
+.namespace ["Getopt::Obj::Spec"]
+
+=item C<__init()>
+
+Set the defaults to all our attributes, more internal stuff. Sets the default
+"type" to C<.Boolean>.
+
+=cut
+
+.sub __init :method
+ $P0 = new .String
+ $P0 = ''
+ setattribute self, "name", $P0
+ # TODO? These next two will be ResizablePMCArray's
+ # to allow the whole --height --length type thing
+ $P0 = new .String
+ $P0 = ''
+ setattribute self, "long", $P0
+ $P0 = new .String
+ $P0 = ''
+ setattribute self, "short", $P0
+ $P0 = new .Boolean
+ $P0 = 0
+ setattribute self, "optarg", $P0
+ $P0 = new .Integer
+ $P0 = .Boolean
+ setattribute self, "type", $P0
+.end
+
+=item C<STRING self."name"()>
+
+=item C<STRING self."name"(STRING val)>
+
+If val is given, set the name to that. If val is not given, return either
+name, long, or short, in that order. Used for the return key. So if you
+define only a short option, but want a long name returned, set this. The
+partial intent of the method is to easily allow having an option have multiple
+long/short arguments instead of one of each.
+
+=cut
+
+.sub name :method
+ .param string val :optional
+ .param int opt :opt_flag
+ unless opt goto else
+ # Setting
+ $P0 = new .String
+ $P0 = val
+ setattribute self, "name", $P0
+ goto endif
+else:
+ # Getting
+ .local pmc tmp
+ $P0 = getattribute self, "name"
+ $S0 = $P0
+ if $S0 != '' goto case_0
+ $S0 = self."long"()
+ if $S0 != '' goto case_1
+ $S0 = self."short"()
+ if $S0 != '' goto case_2
+ # XXX This actually is an error, the program forgot to set name, long, or
+ # short
+ val = ''
+ goto endif
+case_0:
+ $P0 = getattribute self, "name"
+ val = $P0
+ goto endif
+case_1:
+ val = self."long"()
+ goto endif
+case_2:
+ val = self."short"()
+endif:
+ .return(val)
+.end
+
+=item C<STRING self."long"()>
+
+=item C<STRING self."long"(STRING val)>
+
+If val is given, set the long value to that. If val is not given, return the
+string set as the long.
+
+=cut
+
+.sub "long" :method
+ .param string val :optional
+ .param int opt :opt_flag
+ unless opt goto else_0
+ # Setting
+ $P0 = new .String
+ $P0 = val
+ setattribute self, "long", $P0
+ goto endif_0
+else_0:
+ # Getting
+ $P0 = getattribute self, "long"
+ val = $P0
+endif_0:
+ .return(val)
+.end
+
+=item C<STRING self."short"()>
+
+=item C<STRING self."short"(STRING val)>
+
+If val is given, set the short value to that. If val is not given, return the
+string set as the short.
+
+NOTE: There is no checking to ensure that short is only one character.
+
+=cut
+
+.sub "short" :method
+ .param string val :optional
+ .param int opt :opt_flag
+ unless opt goto else_0
+ # Setting
+ $P0 = new .String
+ $P0 = val
+ setattribute self, "short", $P0
+ goto endif_0
+else_0:
+ # Getting
+ $P0 = getattribute self, "short"
+ val = $P0
+endif_0:
+ .return(val)
+.end
+
+=item C<INT self."type"()>
+
+=item C<INT self."type"(INT val)>
+
+If val is given, set the type to that. If val is not given, return the int set
+as the type.
+
+NOTE: It doesn't verify it's a corrent type.
+
+Use the constants:
+
+=over 4
+
+=item C<.Boolean>
+
+A true/false value, the default.
+
+For a short argument, it's simply C<-f>. Groups of C<.Boolean>'s tied
+together, such as C<-foobar>, if C<-f>, C<-o>, C<-b>, C<-a>, and C<-r> are all
+C<.Boolean> values, then each will be set. If C<-f> is a C<.Boolean> but one
+of the others is not, an exception is thrown.
+
+For a long argument, it takes the form C<--foo>. Usage such as C<--foo=this>
+or C<--foo=> are allowed, but it just sets it to true, so no difference.
+
+=item C<.String>
+
+A string. This can take the form of C<--foo=bar>, C<-f bar>, or C<-fbar>.
+
+=item C<.Integer>
+
+An integer, --foo=3.14 is stored as 3. Type conversions are done by Parrot.
+Same forms as for C<.String>.
+
+=item C<.Float>
+
+A float. Same forms apply here as well.
+
+=item C<.Array>
+
+An array, done via multiple arguments. For something such as
+C<-I./include -I./src/include> for example, C<I> will be an array of
+C<./include> and C<./src/include>. If only used once, it's a one sized array.
+
+=item C<.Hash>
+
+A hash, such as defines. For a short argument, the form is C<-Dfoo=bar>,
+C<-Dfoo>, and C<--define=foo=bar>(both equal signs required).
+
+=back
+
+Do not hard code the integer values in, for the same reason as the rest of your
+code. There's no guarantees they won't be reassigned.
+
+=cut
+
+.sub "type" :method
+ .param int val :optional
+ .param int opt :opt_flag
+ unless opt goto else_0
+ # Setting
+ $P0 = new .Integer
+ $P0 = val
+ setattribute self, "type", $P0
+ goto endif_0
+else_0:
+ # Getting
+ $P0 = getattribute self, "type"
+ val = $P0
+endif_0:
+ .return(val)
+.end
+
+=item C<INT self."optarg"()>
+
+=item C<INT self."optarg"(INT val)>
+
+Boolean method, with explicit setting. If optarg is set to a true value, then
+the argument, e.g. C<bar> in C<--foo=bar>, is not mandatory. In
+C<-fbar>, C<-f> is set to C<bar>. In C<-f bar> it is NOT set.
+
+=cut
+
+.sub "optarg" :method
+ .param int val :optional
+ .param int opt :opt_flag
+ unless opt goto else_0
+ # Setting
+ $P0 = new .Boolean
+ $P0 = val
+ setattribute self, "optarg", $P0
+ goto endif_0
+else_0:
+ # Getting
+ $P0 = getattribute self, "optarg"
+ val = $P0
+endif_0:
+ .return(val)
+.end
+
+=back
+
+=head1 TODO
+
+=over 4
+
+=item *
+
+Actually check what's being passed instead of using type conversions?
+
+=item *
+
+Sub type, call a sub for a given argument, with C<argv> and C<return>.
+
+=item *
+
+How to handle an unknown arg, currently kept in argv.
+
+=item *
+
+Should a lonesome hyphen be a permited value as not an option. Currently kept
+in argv in case the program wants it, such as indicating stdin or stdout.
+
+=item *
+
+For an arg to a short arg, e.g. -C -d, will put -d as the value for -C so long
+as -C is not a C<.Boolean>. Should it be an error?
+
+=item *
+
+Should MissingRequired exit or just throw an exception?
+
+=back
+
+=head1 CAVEAT EMPTOR
+
+It's new, not well tested, etc...
+
+=head1 BUGS
+
+=over 4
+
+=item *
+
+If an option is considered optional, then with the short name, the next value
+is not checked for at all. If it's not optional, it's checked and all's well,
+as described for C<obj."type"()>.
+
+Not positive this is a bug... And relates to the -f -b issue where if the
+argument to -f is required, it will be given '-b'.
+
+=item *
+
+Bundling of options will only work for C<.Boolean> options. So my little "perl
+pie" annoyance isn't handled, C<perl -pie "code">, although perl doesn't handle
+it in a DWIM manner...
+
+And it doesn't have good error correction....
+
+=back
+
+=head1 AUTHOR
+
+Joshua Isom - C<[EMAIL PROTECTED]>
+
+=head1 SEE ALSO
+
+The F<library/Getopt/Long.pir> Parrot library.
+
+F<t/library/getopt_obj.t>
+
+=head1 COPYRIGHT
+
+Copyright (C) 2006 The Perl Foundation. All rights reserved.
+This program is free software. It is subject to the same
+license as The Parrot Interpreter.
+
+=cut
+
Added: trunk/t/library/getopt_obj.t
==============================================================================
--- (empty file)
+++ trunk/t/library/getopt_obj.t Wed Jan 11 14:12:39 2006
@@ -0,0 +1,703 @@
+#!perl
+# Copyright: 2001-2005 The Perl Foundation. All Rights Reserved.
+# $Id: getopt_obj.t 10677 2005-12-26 14:05:52Z jisom $
+
+use strict;
+use warnings;
+use lib qw( t . lib ../lib ../../lib );
+use Test::More;
+use Parrot::Test;
+
+
+=head1 NAME
+
+t/library/getopt_obj.t - testing the module Getopt/Obj.pir
+
+=head1 SYNOPSIS
+
+ % prove t/library/getopt_obj.t
+
+=head1 DESCRIPTION
+
+This test program tries to handle command line arguments with the
+module F<runtime/parrot/library/Getopt/Obj.pir>.
+
+=cut
+
+
+# 1
+pir_output_is(<<'CODE', <<'OUT', "basic long options");
+
+.sub main :main
+ .local pmc argv
+ argv = new .ResizablePMCArray
+ push argv, '--foo=bar'
+ push argv, '--bar=3.14'
+ push argv, '--bax=3'
+ push argv, '--baz'
+
+ load_bytecode "Getopt/Obj.pir"
+ .local pmc getopts
+ getopts = new "Getopt::Obj"
+
+ $P0 = getopts."add"()
+ $P0."long"("foo")
+ $P0."type"(.String)
+
+ $P0 = getopts."add"()
+ $P0."long"("bar")
+ $P0."type"(.Float)
+
+ $P0 = getopts."add"()
+ $P0."long"("bax")
+ $P0."type"(.Integer)
+
+ $P0 = getopts."add"()
+ $P0."long"("baz")
+
+ $P1 = getopts."get_options"(argv)
+
+ $S0 = $P1["foo"]
+ print "foo is "
+ print $S0
+ print "\n"
+
+ $S0 = $P1["bar"]
+ print "bar is "
+ print $S0
+ print "\n"
+
+ $S0 = $P1["bax"]
+ print "bax is "
+ print $S0
+ print "\n"
+
+ $S0 = $P1["baz"]
+ print "baz is "
+ print $S0
+ print "\n"
+.end
+
+CODE
+foo is bar
+bar is 3.14
+bax is 3
+baz is 1
+OUT
+
+# 2
+pir_output_is(<<'CODE', <<'OUT', "basic short options");
+.sub main :main
+ .local pmc argv
+ argv = new .ResizablePMCArray
+ push argv, '-f'
+ push argv, 'bar'
+ push argv, '-Abc'
+ push argv, '-c'
+
+ load_bytecode "Getopt/Obj.pir"
+ .local pmc getopts
+ getopts = new "Getopt::Obj"
+
+ $P0 = getopts."add"()
+ $P0."short"("f")
+ $P0."type"(.String)
+
+ $P0 = getopts."add"()
+ $P0."short"("A")
+ $P0."type"(.String)
+
+ $P0 = getopts."add"()
+ $P0."short"("c")
+
+ $P1 = getopts."get_options"(argv)
+
+ $S0 = $P1["f"]
+ print "f is "
+ print $S0
+ print "\n"
+
+ $S0 = $P1["A"]
+ print "A is "
+ print $S0
+ print "\n"
+
+ $S0 = $P1["c"]
+ print "c is "
+ print $S0
+ print "\n"
+.end
+CODE
+f is bar
+A is bc
+c is 1
+OUT
+
+# 3
+pir_output_is(<<'CODE', <<'OUT', "simple array");
+.sub main :main
+ .local pmc argv
+ argv = new .ResizablePMCArray
+ push argv, '-Iinca'
+ push argv, '-Iincb'
+
+ load_bytecode "Getopt/Obj.pir"
+ .local pmc getopts
+ getopts = new "Getopt::Obj"
+
+ $P0 = getopts."add"()
+ $P0."short"("I")
+ $P0."type"(.Array)
+
+ $P1 = getopts."get_options"(argv)
+
+ $S0 = $P1["I";0]
+ print "0 is "
+ print $S0
+ print "\n"
+
+ $S0 = $P1["I";1]
+ print "1 is "
+ print $S0
+ print "\n"
+
+.end
+CODE
+0 is inca
+1 is incb
+OUT
+
+# 4
+pir_output_is(<<'CODE', <<'OUT', "mixing long and short with array");
+.sub main :main
+ .local pmc argv
+ argv = new .ResizablePMCArray
+ push argv, '-Iinca'
+ push argv, '--include=incb'
+
+ load_bytecode "Getopt/Obj.pir"
+ .local pmc getopts
+ getopts = new "Getopt::Obj"
+
+ $P0 = getopts."add"()
+ $P0."long"("include")
+ $P0."short"("I")
+ $P0."type"(.Array)
+
+ $P1 = getopts."get_options"(argv)
+
+ $S0 = $P1["include";0]
+ print "0 is "
+ print $S0
+ print "\n"
+
+ $S0 = $P1["include";1]
+ print "1 is "
+ print $S0
+ print "\n"
+
+.end
+CODE
+0 is inca
+1 is incb
+OUT
+
+# 5
+pir_output_is(<<'CODE', <<'OUT', "hash");
+.sub main :main
+ .local pmc argv
+ argv = new .ResizablePMCArray
+ push argv, '-Dfoo=bar'
+ push argv, '--define=bax=baz'
+ push argv, '-Dfoobar'
+
+ load_bytecode "Getopt/Obj.pir"
+ .local pmc getopts
+ getopts = new "Getopt::Obj"
+
+ $P0 = getopts."add"()
+ $P0."long"("define")
+ $P0."short"("D")
+ $P0."type"(.Hash)
+
+ $P1 = getopts."get_options"(argv)
+
+ $S0 = $P1["define";"foo"]
+ print "foo is "
+ print $S0
+ print "\n"
+
+ $S0 = $P1["define";"bax"]
+ print "bax is "
+ print $S0
+ print "\n"
+
+ $S0 = $P1["define";"foobar"]
+ print "foobar is "
+ print $S0
+ print "\n"
+
+.end
+CODE
+foo is bar
+bax is baz
+foobar is 1
+OUT
+
+# 6
+pir_output_is(<<'CODE', <<'OUT', "bundling short options");
+.sub main :main
+ .local pmc argv
+ argv = new .ResizablePMCArray
+ push argv, '-abc'
+
+ load_bytecode "Getopt/Obj.pir"
+ .local pmc getopts
+ getopts = new "Getopt::Obj"
+
+ $P0 = getopts."add"()
+ $P0."short"("a")
+ $P0 = getopts."add"()
+ $P0."short"("b")
+ $P0 = getopts."add"()
+ $P0."short"("c")
+
+ $P1 = getopts."get_options"(argv)
+
+ $S0 = $P1["a"]
+ print "a is "
+ print $S0
+ print "\n"
+
+ $S0 = $P1["b"]
+ print "b is "
+ print $S0
+ print "\n"
+
+ $S0 = $P1["c"]
+ print "c is "
+ print $S0
+ print "\n"
+
+.end
+CODE
+a is 1
+b is 1
+c is 1
+OUT
+
+# 7
+pir_output_is(<<'CODE', <<'OUT', "ignored options");
+.sub main :main
+ .local pmc argv
+ argv = new .ResizablePMCArray
+ push argv, '--ignore'
+ push argv, '--foo'
+
+ load_bytecode "Getopt/Obj.pir"
+ .local pmc getopts
+ getopts = new "Getopt::Obj"
+
+ $P0 = getopts."add"()
+ $P0."long"("foo")
+
+ $P1 = getopts."get_options"(argv)
+
+ $S0 = $P1["foo"]
+ print "foo is "
+ print $S0
+ print "\n"
+
+ $S0 = argv[0]
+ print "argv[0] is "
+ print $S0
+ print "\n"
+
+.end
+CODE
+foo is 1
+argv[0] is --ignore
+OUT
+
+# 8
+pir_output_is(<<'CODE', <<'OUT', "double dash stop");
+.sub main :main
+ .local pmc argv
+ argv = new .ResizablePMCArray
+ push argv, '--foo'
+ push argv, '--'
+ push argv, '--bar'
+
+ load_bytecode "Getopt/Obj.pir"
+ .local pmc getopts
+ getopts = new "Getopt::Obj"
+
+ $P0 = getopts."add"()
+ $P0."long"("foo")
+ $P0 = getopts."add"()
+ $P0."long"("bar")
+
+ $P1 = getopts."get_options"(argv)
+
+ $S0 = $P1["foo"]
+ print "foo is "
+ print $S0
+ print "\n"
+
+ # Hash sets an nonexistant value to None
+ $S0 = $P1["bar"]
+ print "bar is "
+ print $S0
+ print "\n"
+
+ $S0 = argv[0]
+ print "argv[0] is "
+ print $S0
+ print "\n"
+
+.end
+CODE
+foo is 1
+bar is None
+argv[0] is --bar
+OUT
+
+# 9
+pir_output_is(<<'CODE', <<'OUT', "notOptStop");
+.sub main :main
+ .local pmc argv
+ argv = new .ResizablePMCArray
+ push argv, '--foo'
+ push argv, 'foo'
+ push argv, '--bar'
+
+ load_bytecode "Getopt/Obj.pir"
+ .local pmc getopts
+ getopts = new "Getopt::Obj"
+ getopts."notOptStop"(1)
+
+ $P0 = getopts."add"()
+ $P0."long"("foo")
+ $P0 = getopts."add"()
+ $P0."long"("bar")
+
+ $P1 = getopts."get_options"(argv)
+
+ $S0 = $P1["foo"]
+ print "foo is "
+ print $S0
+ print "\n"
+
+ $S0 = $P1["bar"]
+ print "bar is "
+ print $S0
+ print "\n"
+
+ $S0 = argv[0]
+ print "argv[0] is "
+ print $S0
+ print "\n"
+
+ $S0 = argv[1]
+ print "argv[1] is "
+ print $S0
+ print "\n"
+
+.end
+CODE
+foo is 1
+bar is None
+argv[0] is foo
+argv[1] is --bar
+OUT
+
+# 10
+pir_output_is(<<'CODE', <<'OUT', "optarg");
+.sub main :main
+ .local pmc argv
+ argv = new .ResizablePMCArray
+ push argv, '--foo'
+ push argv, '-f'
+ push argv, '-bbar'
+
+ load_bytecode "Getopt/Obj.pir"
+ .local pmc getopts
+ getopts = new "Getopt::Obj"
+ getopts."notOptStop"(1)
+
+ $P0 = getopts."add"()
+ $P0."long"("foo")
+ $P0."optarg"(1)
+ $P0."type"(.String)
+
+ $P0 = getopts."add"()
+ $P0."short"("f")
+ $P0."optarg"(1)
+ $P0."type"(.String)
+
+ $P0 = getopts."add"()
+ $P0."short"("b")
+ $P0."optarg"(1)
+ $P0."type"(.String)
+
+ $P1 = getopts."get_options"(argv)
+
+ $S0 = $P1["foo"]
+ print "foo is "
+ print $S0
+ print "\n"
+
+ $S0 = $P1["f"]
+ print "f is "
+ print $S0
+ print "\n"
+
+ $S0 = $P1["b"]
+ print "b is "
+ print $S0
+ print "\n"
+
+.end
+CODE
+foo is
+f is
+b is bar
+OUT
+
+# 11
+pir_output_is(<<'CODE', <<'OUT', "pass through");
+.sub main :main
+ .local pmc argv
+ argv = new .ResizablePMCArray
+ push argv, '--foo'
+ push argv, 'foo'
+ push argv, '--bar'
+ push argv, 'bar'
+
+ load_bytecode "Getopt/Obj.pir"
+ .local pmc getopts
+ getopts = new "Getopt::Obj"
+
+ $P0 = getopts."add"()
+ $P0."long"("foo")
+ $P0 = getopts."add"()
+ $P0."long"("bar")
+
+ $P1 = getopts."get_options"(argv)
+
+ $S0 = $P1["foo"]
+ print "foo is "
+ print $S0
+ print "\n"
+
+ $S0 = $P1["bar"]
+ print "bar is "
+ print $S0
+ print "\n"
+
+ $S0 = argv[0]
+ print "argv[0] is "
+ print $S0
+ print "\n"
+
+ $S0 = argv[1]
+ print "argv[1] is "
+ print $S0
+ print "\n"
+
+.end
+CODE
+foo is 1
+bar is 1
+argv[0] is foo
+argv[1] is bar
+OUT
+
+# 12
+pir_output_is(<<'CODE', <<'OUT', "lone dash");
+.sub main :main
+ .local pmc argv
+ argv = new .ResizablePMCArray
+ push argv, '--foo'
+ push argv, '-'
+ push argv, '--bar'
+
+ load_bytecode "Getopt/Obj.pir"
+ .local pmc getopts
+ getopts = new "Getopt::Obj"
+
+ $P0 = getopts."add"()
+ $P0."long"("foo")
+ $P0 = getopts."add"()
+ $P0."long"("bar")
+
+ $P1 = getopts."get_options"(argv)
+
+ $S0 = $P1["foo"]
+ print "foo is "
+ print $S0
+ print "\n"
+
+ $S0 = $P1["bar"]
+ print "bar is "
+ print $S0
+ print "\n"
+
+ $S0 = argv[0]
+ print "argv[0] is "
+ print $S0
+ print "\n"
+
+.end
+CODE
+foo is 1
+bar is 1
+argv[0] is -
+OUT
+
+# 13
+pir_output_is(<<'CODE', <<'OUT', "complex example, touch of everything");
+.include "library/dumper.pir"
+.sub main :main
+ .local pmc argv
+ argv = new .ResizablePMCArray
+ push argv, '-DHi=Hello'
+ push argv, '-DBye=Good Bye'
+ push argv, '-DDefined'
+ push argv, '--define=hi=hello'
+ push argv, '--ignored'
+ push argv, '-i'
+ push argv, '--ignored=hello'
+ push argv, '--foo=file'
+ push argv, '-I/usr/include'
+ push argv, 'argv'
+ push argv, '-I'
+ push argv, '/usr/local/include'
+ push argv, '-abc'
+ push argv, '-e'
+ push argv, 'codea'
+ push argv, 'stay'
+ push argv, '-'
+ push argv, '--bar=3.1'
+ push argv, '--baz=z'
+ push argv, '--ban=3.14'
+ push argv, '--baz'
+ push argv, 'with me'
+ push argv, '-f'
+ push argv, 'file.txt'
+ push argv, '-e'
+ push argv, 'codeb'
+ push argv, '-r'
+ push argv, '12'
+ push argv, '-x'
+ push argv, 'foobar'
+
+ load_bytecode "Getopt/Obj.pir"
+ .local pmc getopts
+ getopts = new "Getopt::Obj"
+
+ $P0 = getopts."add"()
+ $P0."name"("Foo")
+ $P0."long"("foo")
+ $P0."short"("f")
+ $P0."type"(.String)
+
+ $P0 = getopts."add"()
+ $P0."name"("Bar")
+ $P0."long"("bar")
+ $P0."short"("r")
+ $P0."type"(.Integer)
+
+ $P0 = getopts."add"()
+ $P0."long"("ban")
+ $P0."type"(.Float)
+
+ $P0 = getopts."add"()
+ $P0."long"("baz")
+ $P0."short"("z")
+ $P0."type"(.Boolean)
+
+ $P0 = getopts."add"()
+ $P0."name"("FooBar")
+ $P0."long"("foobar")
+ $P0."short"("x")
+ $P0."type"(.String)
+
+ $P0 = getopts."add"()
+ $P0."name"("code")
+ $P0."short"("e")
+ $P0."type"(.Array)
+
+ $P0 = getopts."add"()
+ $P0."short"("I")
+ $P0."type"(.Array)
+
+ $P0 = getopts."add"()
+ $P0."long"("define")
+ $P0."short"("D")
+ $P0."type"(.Hash)
+
+ $P0 = getopts."add"()
+ $P0."name"("alpha")
+ $P0."short"("a")
+ $P0 = getopts."add"()
+ $P0."name"("beta")
+ $P0."short"("b")
+ $P0 = getopts."add"()
+ $P0."name"("cab")
+ $P0."short"("c")
+ $P1 = getopts."get_options"(argv)
+
+ _dumper(argv, "argv")
+ _dumper($P1, "return")
+
+
+.end
+CODE
+"argv" => ResizablePMCArray (size:7) [
+ "--ignored",
+ "-i",
+ "--ignored=hello",
+ "argv",
+ "stay",
+ "-",
+ "with me"
+]
+"return" => Hash {
+ "Bar" => 12,
+ "Foo" => "file.txt",
+ "FooBar" => "foobar",
+ "I" => ResizablePMCArray (size:2) [
+ "/usr/include",
+ "/usr/local/include"
+ ],
+ "alpha" => 1,
+ "ban" => 3.14,
+ "baz" => 1,
+ "beta" => 1,
+ "cab" => 1,
+ "code" => ResizablePMCArray (size:2) [
+ "codea",
+ "codeb"
+ ],
+ "define" => Hash {
+ "Bye" => "Good Bye",
+ "Defined" => 1,
+ "Hi" => "Hello",
+ "hi" => "hello"
+ }
+}
+OUT
+
+=head1 AUTHOR
+
+Joshua Isom - C<[EMAIL PROTECTED]>
+
+=head1 SEE ALSO
+
+F<runtime/parrot/library/Getopt/Obj.pir>
+
+=cut
+
+BEGIN { plan tests => 13; }
+