# 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"};