# New Ticket Created by Matt Kennedy # Please include the string: [perl #30631] # in the subject line of all future correspondence about this issue. # <URL: http://rt.perl.org:80/rt3/Ticket/Display.html?id=30631 >
The attached env.patch patches classes/env.pmc to add vtable methods elements() and get_iter() and modifies get_string_keyed() to also accept integer keys so that it is possible to use an Iterator on the environment. The patch uses the char **environ variable in order to perform the iteration. I've tested it on Mac OS X with gcc 3.1 and Linux with gcc 3.2.2. The envtests.patch patches t/pmc/env.t to add a test case for the iterator operation on the Env pmc. Patches were done against the parrot_2004-07-07_070001 snapshot. -- Matt Kennedy
--- classes/env.pmc.orig 2004-07-07 10:05:01.000000000 -0400 +++ classes/env.pmc 2004-07-07 10:51:40.000000000 -0400 @@ -20,11 +20,49 @@ */ #include "parrot/parrot.h" +extern char **environ; pmclass Env singleton { /* +=item C<INTVAL elements()> + +Returns the number of elements in the environment. + +=cut + +*/ + + INTVAL elements () { + INTVAL rv = 0; + while(environ[rv] != NULL) { rv++; } + return rv; + } + +/* + +=item C<PMC* get_iter()> + +Returns a new iterator for the environment. + +=cut + +*/ + + PMC* get_iter () { + PMC *iter = pmc_new_init(interpreter, enum_class_Iterator, SELF); + PMC *key = pmc_new(interpreter, enum_class_Key); + PMC_struct_val(iter) = key; + PObj_get_FLAGS(key) |= KEY_integer_FLAG; + PMC_int_val(key) = 0; + if(!environ[0]) + PMC_int_val(key) = -1; + return iter; + } + +/* + =item C<STRING *get_string_keyed(PMC *key)> Returns the Parrot string value for the environment variable C<*key>. @@ -34,24 +72,37 @@ */ STRING* get_string_keyed(PMC* key) { - char *keyname = string_to_cstring(interpreter, - VTABLE_get_string(interpreter, key)); int free_it = 0; STRING *retval; - char *val = NULL; + char *keyname, *envp, *p, *val = NULL; - if (keyname) { - val = Parrot_getenv(keyname, &free_it); - string_cstring_free(keyname); - if (val) { - retval = string_from_cstring(interpreter, val, 0); - } else { - retval = string_from_cstring(interpreter, "", 0); - } - } else { - retval = string_from_cstring(interpreter, "", 0); + switch(PObj_get_FLAGS(key) & KEY_type_FLAGS) { + case KEY_integer_FLAG: + if(PMC_int_val(key) < 0) { + retval = string_from_cstring(interpreter, "", 0); + } else { + envp = environ[PMC_int_val(key)]; + p = strchr(envp, '='); + retval = string_from_cstring(interpreter, envp, (p-envp)); + } + break; + default: + keyname = string_to_cstring(interpreter, + VTABLE_get_string(interpreter, key)); + if (keyname) { + val = Parrot_getenv(keyname, &free_it); + string_cstring_free(keyname); + if (val) { + retval = string_from_cstring(interpreter, val, 0); + } else { + retval = string_from_cstring(interpreter, "", 0); + } + } else { + retval = string_from_cstring(interpreter, "", 0); + } + if (free_it && val) mem_sys_free(val); + break; } - if (free_it && val) mem_sys_free(val); return retval; }
--- t/pmc/env.t.orig 2004-07-07 10:44:11.000000000 -0400 +++ t/pmc/env.t 2004-07-07 11:34:44.000000000 -0400 @@ -16,7 +16,7 @@ =cut -use Parrot::Test tests => 6; +use Parrot::Test tests => 7; use Test::More; use Parrot::Config; @@ -89,6 +89,32 @@ ok 2 OUT +output_is(<<'CODE', <<OUT, "iterate"); + new P0, .Env + set P0["PARROT_1"], "hello" + set P0["PARROT_2"], "polly" + iter P1, P0 + set I0, 0 +loop: + unless P1, loopend + shift S2, P1 + eq S2, "PARROT_1", gotit + eq S2, "PARROT_2", gotit + branch notit +gotit: + inc I0 +notit: + branch loop +loopend: + eq I0, 2, isok + print "not " +isok: + print "ok\n" + end +CODE +ok +OUT + SKIP: { # won't work on our unsetenv implementation skip("no native unsetenv", 1) unless $PConfig{"unsetenv"};