[macruby-changes] [3430] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed Feb 3 21:30:00 PST 2010


Revision: 3430
          http://trac.macosforge.org/projects/ruby/changeset/3430
Author:   lsansonetti at apple.com
Date:     2010-02-03 21:29:57 -0800 (Wed, 03 Feb 2010)
Log Message:
-----------
moved the ENV stuff into a separate file

Modified Paths:
--------------
    MacRuby/trunk/hash.c
    MacRuby/trunk/rakelib/builder/builder.rb

Added Paths:
-----------
    MacRuby/trunk/env.c

Added: MacRuby/trunk/env.c
===================================================================
--- MacRuby/trunk/env.c	                        (rev 0)
+++ MacRuby/trunk/env.c	2010-02-04 05:29:57 UTC (rev 3430)
@@ -0,0 +1,741 @@
+/* 
+ * MacRuby implementation of ENV.
+ *
+ * This file is covered by the Ruby license. See COPYING for more details.
+ * 
+ * Copyright (C) 2007-2010, Apple Inc. All rights reserved.
+ * Copyright (C) 1993-2007 Yukihiro Matsumoto
+ * Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
+ * Copyright (C) 2000 Information-technology Promotion Agency, Japan
+ */
+
+#include "ruby/ruby.h"
+#include "ruby/st.h"
+#include "ruby/util.h"
+#include "ruby/node.h"
+#include "vm.h"
+
+#include <crt_externs.h>
+
+static VALUE envtbl;
+
+static int path_tainted = -1;
+
+static char **origenviron;
+#define GET_ENVIRON() (*_NSGetEnviron())
+
+static VALUE
+to_hash(VALUE hash)
+{
+    return rb_convert_type(hash, T_HASH, "Hash", "to_hash");
+}
+
+static VALUE
+env_str_new(const char *ptr, long len)
+{
+    VALUE str = rb_tainted_str_new(ptr, len);
+    rb_obj_freeze(str);
+    return str;
+}
+
+static VALUE
+env_str_new2(const char *ptr)
+{
+    if (ptr == NULL) {
+	return Qnil;
+    }
+    return env_str_new(ptr, strlen(ptr));
+}
+
+static VALUE
+env_delete(VALUE obj, VALUE name)
+{
+    rb_secure(4);
+    SafeStringValue(name);
+    const char *nam = RSTRING_PTR(name);
+    if (strlen(nam) != RSTRING_LEN(name)) {
+	rb_raise(rb_eArgError, "bad environment variable name");
+    }
+    const char *val = getenv(nam);
+    if (val != NULL) {
+	VALUE value = env_str_new2(val);
+	ruby_setenv(nam, 0);
+	if (strcmp(nam, PATH_ENV) == 0) {
+	    path_tainted = 0;
+	}
+	return value;
+    }
+    return Qnil;
+}
+
+static VALUE
+env_delete_m(VALUE obj, SEL sel, VALUE name)
+{
+    VALUE val = env_delete(obj, name);
+    if (NIL_P(val) && rb_block_given_p()) {
+	rb_yield(name);
+    }
+    return val;
+}
+
+static VALUE
+rb_f_getenv(VALUE obj, SEL sel, VALUE name)
+{
+    rb_secure(4);
+    SafeStringValue(name);
+    const char *nam = RSTRING_PTR(name);
+    if (strlen(nam) != RSTRING_LEN(name)) {
+	rb_raise(rb_eArgError, "bad environment variable name");
+    }
+    const char *env = getenv(nam);
+    if (env != NULL) {
+	if (strcmp(nam, PATH_ENV) == 0 && !rb_env_path_tainted()) {
+	    VALUE str = rb_str_new2(env);
+	    rb_obj_freeze(str);
+	    return str;
+	}
+	return env_str_new2(env);
+    }
+    return Qnil;
+}
+
+static VALUE
+env_fetch(VALUE rcv, SEL sel, int argc, VALUE *argv)
+{
+    rb_secure(4);
+
+    VALUE key, if_none;
+    rb_scan_args(argc, argv, "11", &key, &if_none);
+
+    const bool block_given = rb_block_given_p();
+    if (block_given && argc == 2) {
+	rb_warn("block supersedes default value argument");
+    }
+    SafeStringValue(key);
+    const char *nam = RSTRING_PTR(key);
+    if (strlen(nam) != RSTRING_LEN(key)) {
+	rb_raise(rb_eArgError, "bad environment variable name");
+    }
+    const char *env = getenv(nam);
+    if (env == NULL) {
+	if (block_given) {
+	    return rb_yield(key);
+	}
+	if (argc == 1) {
+	    rb_raise(rb_eKeyError, "key not found");
+	}
+	return if_none;
+    }
+    if (strcmp(nam, PATH_ENV) == 0 && !rb_env_path_tainted()) {
+	return rb_str_new2(env);
+    }
+    return env_str_new2(env);
+}
+
+static void
+path_tainted_p(const char *path)
+{
+    path_tainted = rb_path_check(path) ? 0 : 1;
+}
+
+int
+rb_env_path_tainted(void)
+{
+    if (path_tainted < 0) {
+	path_tainted_p(getenv(PATH_ENV));
+    }
+    return path_tainted;
+}
+
+void
+ruby_setenv(const char *name, const char *value)
+{
+#undef setenv
+#undef unsetenv
+    if (value != NULL) {
+	setenv(name, value, 1);
+    }
+    else {
+	unsetenv(name);
+    }
+}
+
+void
+ruby_unsetenv(const char *name)
+{
+    ruby_setenv(name, 0);
+}
+
+static VALUE
+env_aset(VALUE obj, SEL sel, VALUE nm, VALUE val)
+{
+    if (rb_safe_level() >= 4) {
+	rb_raise(rb_eSecurityError, "can't change environment variable");
+    }
+
+    if (NIL_P(val)) {
+	env_delete(obj, nm);
+	return Qnil;
+    }
+    StringValue(nm);
+    StringValue(val);
+    const char *name = RSTRING_PTR(nm);
+    const char *value = RSTRING_PTR(val);
+    if (strlen(name) != RSTRING_LEN(nm)) {
+	rb_raise(rb_eArgError, "bad environment variable name");
+    }
+    if (strlen(value) != RSTRING_LEN(val)) {
+	rb_raise(rb_eArgError, "bad environment variable value");
+    }
+
+    ruby_setenv(name, value);
+    if (strcmp(name, PATH_ENV) == 0) {
+	if (OBJ_TAINTED(val)) {
+	    /* already tainted, no check */
+	    path_tainted = 1;
+	    return val;
+	}
+	else {
+	    path_tainted_p(value);
+	}
+    }
+    return val;
+}
+
+static VALUE
+env_keys(VALUE rcv, SEL sel)
+{
+    rb_secure(4);
+
+    VALUE ary = rb_ary_new();
+    char **env = GET_ENVIRON();
+    while (*env != NULL) {
+	const char *s = strchr(*env, '=');
+	if (s != NULL) {
+	    rb_ary_push(ary, env_str_new(*env, s - *env));
+	}
+	env++;
+    }
+    return ary;
+}
+
+static VALUE
+env_each_key(VALUE ehash, SEL sel)
+{
+    RETURN_ENUMERATOR(ehash, 0, 0);
+    VALUE keys = env_keys(Qnil, 0);	/* rb_secure(4); */
+    for (long i = 0, count = RARRAY_LEN(keys); i < count; i++) {
+	rb_yield(RARRAY_AT(keys, i));
+	RETURN_IF_BROKEN();
+    }
+    return ehash;
+}
+
+static VALUE
+env_values(VALUE rcv, SEL sel)
+{
+    rb_secure(4);
+
+    VALUE ary = rb_ary_new();
+    char **env = GET_ENVIRON();
+    while (*env != NULL) {
+	const char *s = strchr(*env, '=');
+	if (s != NULL) {
+	    rb_ary_push(ary, env_str_new2(s + 1));
+	}
+	env++;
+    }
+    return ary;
+}
+
+static VALUE
+env_each_value(VALUE ehash, SEL sel)
+{
+    RETURN_ENUMERATOR(ehash, 0, 0);
+    VALUE values = env_values(Qnil, 0);	/* rb_secure(4); */
+    for (long i = 0, count = RARRAY_LEN(values); i < count; i++) {
+	rb_yield(RARRAY_AT(values, i));
+	RETURN_IF_BROKEN();
+    }
+    return ehash;
+}
+
+static VALUE
+env_each_pair(VALUE ehash, SEL sel)
+{
+    RETURN_ENUMERATOR(ehash, 0, 0);
+
+    rb_secure(4);
+    VALUE ary = rb_ary_new();
+    char **env = GET_ENVIRON();
+    while (*env != NULL) {
+	const char *s = strchr(*env, '=');
+	if (s != NULL) {
+	    rb_ary_push(ary, env_str_new(*env, s - *env));
+	    rb_ary_push(ary, env_str_new2(s + 1));
+	}
+	env++;
+    }
+
+    for (long i = 0, count = RARRAY_LEN(ary); i < count; i += 2) {
+	rb_yield(rb_assoc_new(RARRAY_AT(ary, i), RARRAY_AT(ary, i + 1)));
+	RETURN_IF_BROKEN();
+    }
+    return ehash;
+}
+
+static VALUE
+env_reject_bang(VALUE ehash, SEL sel)
+{
+    RETURN_ENUMERATOR(ehash, 0, 0);
+    VALUE keys = env_keys(Qnil, 0);	/* rb_secure(4); */
+    bool deleted = false;
+    for (long i = 0, count = RARRAY_LEN(keys); i < count; i++) {
+	VALUE key = RARRAY_AT(keys, i);
+	VALUE val = rb_f_getenv(Qnil, 0, key);
+	if (!NIL_P(val)) {
+	    VALUE v = rb_yield_values(2, key, val);
+	    RETURN_IF_BROKEN();
+	    if (RTEST(v)) {
+		rb_obj_untaint(key);
+		env_delete(Qnil, key);
+		deleted = true;
+	    }
+	}
+    }
+    return deleted ? envtbl : Qnil;
+}
+
+static VALUE
+env_delete_if(VALUE ehash, SEL sel)
+{
+    RETURN_ENUMERATOR(ehash, 0, 0);
+    env_reject_bang(ehash, 0);
+    return envtbl;
+}
+
+static VALUE
+env_values_at(VALUE rcv, SEL sel, int argc, VALUE *argv)
+{
+    rb_secure(4);
+    VALUE result = rb_ary_new();
+    for (long i = 0; i < argc; i++) {
+	rb_ary_push(result, rb_f_getenv(Qnil, 0, argv[i]));
+    }
+    return result;
+}
+
+static VALUE
+env_select(VALUE ehash, SEL sel)
+{
+    RETURN_ENUMERATOR(ehash, 0, 0);
+    rb_secure(4);
+    VALUE result = rb_hash_new();
+    char **env = GET_ENVIRON();
+    while (*env != NULL) {
+	const char *s = strchr(*env, '=');
+	if (s != NULL) {
+	    VALUE k = env_str_new(*env, s - *env);
+	    VALUE v = env_str_new2(s + 1);
+	    VALUE v2 = rb_yield_values(2, k, v);
+	    RETURN_IF_BROKEN();
+	    if (RTEST(v2)) {
+		rb_hash_aset(result, k, v);
+	    }
+	}
+	env++;
+    }
+    return result;
+}
+
+static VALUE
+rb_env_clear_imp(VALUE rcv, SEL sel)
+{
+    VALUE keys = env_keys(Qnil, 0);	/* rb_secure(4); */
+    for (long i = 0, count = RARRAY_LEN(keys); i < count; i++) {
+	VALUE val = rb_f_getenv(Qnil, 0, RARRAY_AT(keys, i));
+	if (!NIL_P(val)) {
+	    env_delete(Qnil, RARRAY_AT(keys, i));
+	}
+    }
+    return envtbl;
+}
+
+VALUE
+rb_env_clear(void)
+{
+    return rb_env_clear_imp(Qnil, 0);
+}
+
+static VALUE
+env_to_s(VALUE rcv, SEL sel)
+{
+    return rb_usascii_str_new2("ENV");
+}
+
+static VALUE
+env_inspect(VALUE rcv, SEL sel)
+{
+    rb_secure(4);
+
+    VALUE str = rb_str_buf_new2("{");
+    char **env = GET_ENVIRON();
+    while (*env != NULL) {
+	const char *s = strchr(*env, '=');
+
+	if (env != GET_ENVIRON()) {
+	    rb_str_buf_cat2(str, ", ");
+	}
+	if (s != NULL) {
+	    rb_str_buf_cat2(str, "\"");
+	    rb_str_buf_cat(str, *env, s - *env);
+	    rb_str_buf_cat2(str, "\"=>");
+	    VALUE i = rb_inspect(rb_str_new2(s + 1));
+	    rb_str_buf_append(str, i);
+	}
+	env++;
+    }
+    rb_str_buf_cat2(str, "}");
+    OBJ_TAINT(str);
+
+    return str;
+}
+
+static VALUE
+env_to_a(VALUE rcv, SEL sel)
+{
+    rb_secure(4);
+
+    VALUE ary = rb_ary_new();
+    char **env = GET_ENVIRON();
+    while (*env != NULL) {
+	const char *s = strchr(*env, '=');
+	if (s != NULL) {
+	    rb_ary_push(ary, rb_assoc_new(env_str_new(*env, s - *env),
+			env_str_new2(s + 1)));
+	}
+	env++;
+    }
+    return ary;
+}
+
+static VALUE
+env_none(VALUE rcv, SEL sel)
+{
+    return Qnil;
+}
+
+static VALUE
+env_size(VALUE rcv, SEL sel)
+{
+    rb_secure(4);
+
+    char **env = GET_ENVIRON();
+    int i = 0;
+    while (env[i] != NULL) {
+	i++;
+    }
+    return INT2FIX(i);
+}
+
+static VALUE
+env_empty_p(VALUE rcv, SEL sel)
+{
+    rb_secure(4);
+
+    char **env = GET_ENVIRON();
+    if (env[0] == NULL) {
+	return Qtrue;
+    }
+    return Qfalse;
+}
+
+static VALUE
+env_has_key(VALUE env, SEL sel, VALUE key)
+{
+    rb_secure(4);
+
+    const char *s = StringValuePtr(key);
+    if (strlen(s) != RSTRING_LEN(key)) {
+	rb_raise(rb_eArgError, "bad environment variable name");
+    }
+    if (getenv(s) != NULL) {
+	return Qtrue;
+    }
+    return Qfalse;
+}
+
+static VALUE
+env_assoc(VALUE env, SEL sel, VALUE key)
+{
+    rb_secure(4);
+
+    const char *s = StringValuePtr(key);
+    if (strlen(s) != RSTRING_LEN(key)) {
+	rb_raise(rb_eArgError, "bad environment variable name");
+    }
+    const char *e = getenv(s);
+    if (e != NULL) {
+	return rb_assoc_new(key, rb_tainted_str_new2(e));
+    }
+    return Qnil;
+}
+
+static VALUE
+env_has_value(VALUE dmy, SEL sel, VALUE obj)
+{
+    rb_secure(4);
+
+    obj = rb_check_string_type(obj);
+    if (NIL_P(obj)) {
+	return Qnil;
+    }
+    char **env = GET_ENVIRON();
+    while (*env != NULL) {
+	const char *s = strchr(*env, '=');
+	if (s++ != NULL) {
+	    const long len = strlen(s);
+	    if (RSTRING_LEN(obj) == len
+		    && strncmp(s, RSTRING_PTR(obj), len) == 0) {
+		return Qtrue;
+	    }
+	}
+	env++;
+    }
+    return Qfalse;
+}
+
+static VALUE
+env_rassoc(VALUE dmy, VALUE obj)
+{
+    rb_secure(4);
+
+    obj = rb_check_string_type(obj);
+    if (NIL_P(obj)) {
+	return Qnil;
+    }
+    char **env = GET_ENVIRON();
+    while (*env != NULL) {
+	const char *s = strchr(*env, '=');
+	if (s++ != NULL) {
+	    const long len = strlen(s);
+	    if (RSTRING_LEN(obj) == len
+		    && strncmp(s, RSTRING_PTR(obj), len) == 0) {
+		return rb_assoc_new(rb_tainted_str_new(*env, s - *env - 1),
+			obj);
+	    }
+	}
+	env++;
+    }
+    return Qnil;
+}
+
+static VALUE
+env_key(VALUE dmy, SEL sel, VALUE value)
+{
+    rb_secure(4);
+
+    StringValue(value);
+    char **env = GET_ENVIRON();
+    while (*env != NULL) {
+	const char *s = strchr(*env, '=');
+	if (s++ != NULL) {
+	    const long len = strlen(s);
+	    if (RSTRING_LEN(value) == len
+		    && strncmp(s, RSTRING_PTR(value), len) == 0) {
+		return env_str_new(*env, s - *env - 1);
+	    }
+	}
+	env++;
+    }
+    return Qnil;
+}
+
+static VALUE
+env_index(VALUE dmy, SEL sel, VALUE value)
+{
+    rb_warn("ENV.index is deprecated; use ENV.key");
+    return env_key(dmy, 0, value);
+}
+
+static VALUE
+env_to_hash(VALUE rcv, SEL sel)
+{
+    rb_secure(4);
+
+    VALUE hash = rb_hash_new();
+    char **env = GET_ENVIRON();
+    while (*env != NULL) {
+	const char *s = strchr(*env, '=');
+	if (s != NULL) {
+	    rb_hash_aset(hash, env_str_new(*env, s - *env),
+		    env_str_new2(s + 1));
+	}
+	env++;
+    }
+    return hash;
+}
+
+static VALUE
+env_reject(VALUE rcv, SEL sel)
+{
+    rb_secure(4);
+
+    RETURN_ENUMERATOR(rcv, 0, 0);
+
+    VALUE hash = rb_hash_new();
+    char **env = GET_ENVIRON();
+    while (*env != NULL) {
+	const char *s = strchr(*env, '=');
+	if (s != NULL) {
+	    VALUE key = env_str_new(*env, s - *env);
+	    VALUE val = env_str_new2(s + 1);
+	    if (!RTEST(rb_yield_values(2, key, val))) {
+		rb_hash_aset(hash, key, val);
+	    }
+	}
+	env++;
+    }
+    return hash;
+}
+
+static VALUE
+env_shift(VALUE rcv, SEL sel)
+{
+    rb_secure(4);
+
+    char **env = GET_ENVIRON();
+    if (*env != NULL) {
+	const char *s = strchr(*env, '=');
+	if (s != NULL) {
+	    VALUE key = env_str_new(*env, s - *env);
+	    VALUE val = env_str_new2(getenv(RSTRING_PTR(key)));
+	    env_delete(Qnil, key);
+	    return rb_assoc_new(key, val);
+	}
+    }
+    return Qnil;
+}
+
+static VALUE
+env_invert(VALUE rcv, SEL sel)
+{
+    rb_secure(4);
+
+    VALUE hash = rb_hash_new();
+    char **env = GET_ENVIRON();
+    while (*env != NULL) {
+	const char *s = strchr(*env, '=');
+	if (s != NULL) {
+	    rb_hash_aset(hash, env_str_new2(s + 1),
+		    env_str_new(*env, s - *env));
+	}
+	env++;
+    }
+    return hash;
+}
+
+static int
+env_replace_i(VALUE key, VALUE val, VALUE keys)
+{
+    if (key != Qundef) {
+	env_aset(Qnil, 0, key, val);
+	if (rb_ary_includes(keys, key)) {
+	    rb_ary_delete(keys, key);
+	}
+    }
+    return ST_CONTINUE;
+}
+
+static VALUE
+env_replace(VALUE env, SEL sel, VALUE hash)
+{
+    VALUE keys = env_keys(Qnil, 0);	/* rb_secure(4); */
+    if (env == hash) {
+	return env;
+    }
+    hash = to_hash(hash);
+    rb_hash_foreach(hash, env_replace_i, keys);
+
+    for (long i = 0, count = RARRAY_LEN(keys); i < count; i++) {
+	env_delete(env, RARRAY_AT(keys, i));
+    }
+    return env;
+}
+
+static int
+env_update_i(VALUE key, VALUE val)
+{
+    if (key != Qundef) {
+	if (rb_block_given_p()) {
+	    val = rb_yield_values(3, key, rb_f_getenv(Qnil, 0, key), val);
+	    RETURN_IF_BROKEN();
+	}
+	env_aset(Qnil, 0, key, val);
+    }
+    return ST_CONTINUE;
+}
+
+static VALUE
+env_update(VALUE env, SEL sel, VALUE hash)
+{
+    rb_secure(4);
+    if (env == hash) {
+	return env;
+    }
+    hash = to_hash(hash);
+    rb_hash_foreach(hash, env_update_i, 0);
+    return env;
+}
+
+void
+Init_ENV(void)
+{
+    origenviron = GET_ENVIRON();
+    envtbl = rb_obj_alloc(rb_cObject);
+    rb_extend_object(envtbl, rb_mEnumerable);
+
+    VALUE klass = rb_singleton_class(envtbl);
+
+    rb_objc_define_method(klass, "[]", rb_f_getenv, 1);
+    rb_objc_define_method(klass, "fetch", env_fetch, -1);
+    rb_objc_define_method(klass, "[]=", env_aset, 2);
+    rb_objc_define_method(klass, "store", env_aset, 2);
+    rb_objc_define_method(klass, "each", env_each_pair, 0);
+    rb_objc_define_method(klass, "each_pair", env_each_pair, 0);
+    rb_objc_define_method(klass, "each_key", env_each_key, 0);
+    rb_objc_define_method(klass, "each_value", env_each_value, 0);
+    rb_objc_define_method(klass, "delete", env_delete_m, 1);
+    rb_objc_define_method(klass, "delete_if", env_delete_if, 0);
+    rb_objc_define_method(klass, "clear", rb_env_clear_imp, 0);
+    rb_objc_define_method(klass, "reject", env_reject, 0);
+    rb_objc_define_method(klass, "reject!", env_reject_bang, 0);
+    rb_objc_define_method(klass, "select", env_select, 0);
+    rb_objc_define_method(klass, "shift", env_shift, 0);
+    rb_objc_define_method(klass, "invert", env_invert, 0);
+    rb_objc_define_method(klass, "replace", env_replace, 1);
+    rb_objc_define_method(klass, "update", env_update, 1);
+    rb_objc_define_method(klass, "inspect", env_inspect, 0);
+    rb_objc_define_method(klass, "rehash", env_none, 0);
+    rb_objc_define_method(klass, "to_a", env_to_a, 0);
+    rb_objc_define_method(klass, "to_s", env_to_s, 0);
+    rb_objc_define_method(klass, "key", env_key, 1);
+    rb_objc_define_method(klass, "index", env_index, 1);
+    rb_objc_define_method(klass, "size", env_size, 0);
+    rb_objc_define_method(klass, "length", env_size, 0);
+    rb_objc_define_method(klass, "empty?", env_empty_p, 0);
+    rb_objc_define_method(klass, "keys", env_keys, 0);
+    rb_objc_define_method(klass, "values", env_values, 0);
+    rb_objc_define_method(klass, "values_at", env_values_at, -1);
+    rb_objc_define_method(klass, "include?", env_has_key, 1);
+    rb_objc_define_method(klass, "member?", env_has_key, 1);
+    rb_objc_define_method(klass, "has_key?", env_has_key, 1);
+    rb_objc_define_method(klass, "has_value?", env_has_value, 1);
+    rb_objc_define_method(klass, "key?", env_has_key, 1);
+    rb_objc_define_method(klass, "value?", env_has_value, 1);
+    rb_objc_define_method(klass, "to_hash", env_to_hash, 0);
+    rb_objc_define_method(klass, "assoc", env_assoc, 1);
+    rb_objc_define_method(klass, "rassoc", env_rassoc, 1);
+
+    rb_define_global_const("ENV", envtbl);
+}

Modified: MacRuby/trunk/hash.c
===================================================================
--- MacRuby/trunk/hash.c	2010-02-04 02:10:07 UTC (rev 3429)
+++ MacRuby/trunk/hash.c	2010-02-04 05:29:57 UTC (rev 3430)
@@ -18,8 +18,6 @@
 #include "objc.h"
 #include "vm.h"
 
-#include <crt_externs.h>
-
 static VALUE rhash_try_convert(VALUE, SEL, VALUE);
 
 VALUE
@@ -61,7 +59,6 @@
     return __klass_is_rhash(klass);
 }
 
-static VALUE envtbl;
 static ID id_yield;
 
 static void *defaultCache = NULL;
@@ -1853,709 +1850,6 @@
     return Qfalse;
 }
 
-static int path_tainted = -1;
-
-static char **origenviron;
-#undef environ
-#define environ (*_NSGetEnviron())
-#define GET_ENVIRON(e) (e)
-#define FREE_ENVIRON(e)
-
-static VALUE
-env_str_new(const char *ptr, long len)
-{
-    VALUE str = rb_tainted_str_new(ptr, len);
-
-    rb_obj_freeze(str);
-    return str;
-}
-
-static VALUE
-env_str_new2(const char *ptr)
-{
-    if (!ptr) return Qnil;
-    return env_str_new(ptr, strlen(ptr));
-}
-
-static VALUE
-env_delete(VALUE obj, VALUE name)
-{
-    const char *nam, *val;
-
-    rb_secure(4);
-    SafeStringValue(name);
-    nam = RSTRING_PTR(name);
-    if (strlen(nam) != RSTRING_LEN(name)) {
-	rb_raise(rb_eArgError, "bad environment variable name");
-    }
-    val = getenv(nam);
-    if (val) {
-	VALUE value = env_str_new2(val);
-
-	ruby_setenv(nam, 0);
-#ifdef ENV_IGNORECASE
-	if (STRCASECMP(nam, PATH_ENV) == 0)
-#else
-	if (strcmp(nam, PATH_ENV) == 0)
-#endif
-	{
-	    path_tainted = 0;
-	}
-	return value;
-    }
-    return Qnil;
-}
-
-static VALUE
-env_delete_m(VALUE obj, SEL sel, VALUE name)
-{
-    VALUE val;
-
-    val = env_delete(obj, name);
-    if (NIL_P(val) && rb_block_given_p()) rb_yield(name);
-    return val;
-}
-
-static VALUE
-rb_f_getenv(VALUE obj, SEL sel, VALUE name)
-{
-    const char *nam, *env;
-
-    rb_secure(4);
-    SafeStringValue(name);
-    nam = RSTRING_PTR(name);
-    if (strlen(nam) != RSTRING_LEN(name)) {
-	rb_raise(rb_eArgError, "bad environment variable name");
-    }
-    env = getenv(nam);
-    if (env) {
-#ifdef ENV_IGNORECASE
-	if (STRCASECMP(nam, PATH_ENV) == 0 && !rb_env_path_tainted())
-#else
-	if (strcmp(nam, PATH_ENV) == 0 && !rb_env_path_tainted())
-#endif
-	{
-	    VALUE str = rb_str_new2(env);
-
-	    rb_obj_freeze(str);
-	    return str;
-	}
-	return env_str_new2(env);
-    }
-    return Qnil;
-}
-
-static VALUE
-env_fetch(VALUE rcv, SEL sel, int argc, VALUE *argv)
-{
-    VALUE key, if_none;
-    long block_given;
-    const char *nam, *env;
-
-    rb_secure(4);
-    rb_scan_args(argc, argv, "11", &key, &if_none);
-    block_given = rb_block_given_p();
-    if (block_given && argc == 2) {
-	rb_warn("block supersedes default value argument");
-    }
-    SafeStringValue(key);
-    nam = RSTRING_PTR(key);
-    if (strlen(nam) != RSTRING_LEN(key)) {
-	rb_raise(rb_eArgError, "bad environment variable name");
-    }
-    env = getenv(nam);
-    if (!env) {
-	if (block_given) return rb_yield(key);
-	if (argc == 1) {
-	    rb_raise(rb_eKeyError, "key not found");
-	}
-	return if_none;
-    }
-#ifdef ENV_IGNORECASE
-    if (STRCASECMP(nam, PATH_ENV) == 0 && !rb_env_path_tainted())
-#else
-    if (strcmp(nam, PATH_ENV) == 0 && !rb_env_path_tainted())
-#endif
-	return rb_str_new2(env);
-    return env_str_new2(env);
-}
-
-static void
-path_tainted_p(const char *path)
-{
-    path_tainted = rb_path_check(path)?0:1;
-}
-
-int
-rb_env_path_tainted(void)
-{
-    if (path_tainted < 0) {
-	path_tainted_p(getenv(PATH_ENV));
-    }
-    return path_tainted;
-}
-
-void
-ruby_setenv(const char *name, const char *value)
-{
-#undef setenv
-#undef unsetenv
-    if (value)
-	setenv(name,value,1);
-    else
-	unsetenv(name);
-}
-
-void
-ruby_unsetenv(const char *name)
-{
-    ruby_setenv(name, 0);
-}
-
-static VALUE
-env_aset(VALUE obj, SEL sel, VALUE nm, VALUE val)
-{
-    const char *name, *value;
-
-    if (rb_safe_level() >= 4) {
-	rb_raise(rb_eSecurityError, "can't change environment variable");
-    }
-
-    if (NIL_P(val)) {
-	env_delete(obj, nm);
-	return Qnil;
-    }
-    StringValue(nm);
-    StringValue(val);
-    name = RSTRING_PTR(nm);
-    value = RSTRING_PTR(val);
-    if (strlen(name) != RSTRING_LEN(nm)) {
-	rb_raise(rb_eArgError, "bad environment variable name");
-    }
-    if (strlen(value) != RSTRING_LEN(val)) {
-	rb_raise(rb_eArgError, "bad environment variable value");
-    }
-
-    ruby_setenv(name, value);
-#ifdef ENV_IGNORECASE
-    if (STRCASECMP(name, PATH_ENV) == 0) {
-#else
-    if (strcmp(name, PATH_ENV) == 0) {
-#endif
-	if (OBJ_TAINTED(val)) {
-	    /* already tainted, no check */
-	    path_tainted = 1;
-	    return val;
-	}
-	else {
-	    path_tainted_p(value);
-	}
-    }
-    return val;
-}
-
-static VALUE
-env_keys(VALUE rcv, SEL sel)
-{
-    char **env;
-    VALUE ary;
-
-    rb_secure(4);
-    ary = rb_ary_new();
-    env = GET_ENVIRON(environ);
-    while (*env) {
-	char *s = strchr(*env, '=');
-	if (s) {
-	    rb_ary_push(ary, env_str_new(*env, s-*env));
-	}
-	env++;
-    }
-    FREE_ENVIRON(environ);
-    return ary;
-}
-
-static VALUE
-env_each_key(VALUE ehash, SEL sel)
-{
-    VALUE keys;
-    long i;
-
-    RETURN_ENUMERATOR(ehash, 0, 0);
-    keys = env_keys(Qnil, 0);	/* rb_secure(4); */
-    for (i=0; i<RARRAY_LEN(keys); i++) {
-	rb_yield(RARRAY_AT(keys, i));
-	RETURN_IF_BROKEN();
-    }
-    return ehash;
-}
-
-static VALUE
-env_values(VALUE rcv, SEL sel)
-{
-    VALUE ary;
-    char **env;
-
-    rb_secure(4);
-    ary = rb_ary_new();
-    env = GET_ENVIRON(environ);
-    while (*env) {
-	char *s = strchr(*env, '=');
-	if (s) {
-	    rb_ary_push(ary, env_str_new2(s+1));
-	}
-	env++;
-    }
-    FREE_ENVIRON(environ);
-    return ary;
-}
-
-static VALUE
-env_each_value(VALUE ehash, SEL sel)
-{
-    VALUE values;
-    long i;
-
-    RETURN_ENUMERATOR(ehash, 0, 0);
-    values = env_values(Qnil, 0);	/* rb_secure(4); */
-    for (i=0; i<RARRAY_LEN(values); i++) {
-	rb_yield(RARRAY_AT(values, i));
-	RETURN_IF_BROKEN();
-    }
-    return ehash;
-}
-
-static VALUE
-env_each_pair(VALUE ehash, SEL sel)
-{
-    char **env;
-    VALUE ary;
-    long i;
-
-    RETURN_ENUMERATOR(ehash, 0, 0);
-
-    rb_secure(4);
-    ary = rb_ary_new();
-    env = GET_ENVIRON(environ);
-    while (*env) {
-	char *s = strchr(*env, '=');
-	if (s) {
-	    rb_ary_push(ary, env_str_new(*env, s-*env));
-	    rb_ary_push(ary, env_str_new2(s+1));
-	}
-	env++;
-    }
-    FREE_ENVIRON(environ);
-
-    for (i=0; i<RARRAY_LEN(ary); i+=2) {
-	rb_yield(rb_assoc_new(RARRAY_AT(ary, i), RARRAY_AT(ary, i+1)));
-	RETURN_IF_BROKEN();
-    }
-    return ehash;
-}
-
-static VALUE
-env_reject_bang(VALUE ehash, SEL sel)
-{
-    volatile VALUE keys;
-    long i;
-    int del = 0;
-
-    RETURN_ENUMERATOR(ehash, 0, 0);
-    keys = env_keys(Qnil, 0);	/* rb_secure(4); */
-    for (i=0; i<RARRAY_LEN(keys); i++) {
-	VALUE val = rb_f_getenv(Qnil, 0, RARRAY_AT(keys, i));
-	if (!NIL_P(val)) {
-	    VALUE v = rb_yield_values(2, RARRAY_AT(keys, i), val);
-	    RETURN_IF_BROKEN();
-	    if (RTEST(v)) {
-		rb_obj_untaint(RARRAY_AT(keys, i));
-		env_delete(Qnil, RARRAY_AT(keys, i));
-		del++;
-	    }
-	}
-    }
-    if (del == 0) return Qnil;
-    return envtbl;
-}
-
-static VALUE
-env_delete_if(VALUE ehash, SEL sel)
-{
-    RETURN_ENUMERATOR(ehash, 0, 0);
-    env_reject_bang(ehash, 0);
-    return envtbl;
-}
-
-static VALUE
-env_values_at(VALUE rcv, SEL sel, int argc, VALUE *argv)
-{
-    VALUE result;
-    long i;
-
-    rb_secure(4);
-    result = rb_ary_new();
-    for (i=0; i<argc; i++) {
-	rb_ary_push(result, rb_f_getenv(Qnil, 0, argv[i]));
-    }
-    return result;
-}
-
-static VALUE
-env_select(VALUE ehash, SEL sel)
-{
-    VALUE result;
-    char **env;
-
-    RETURN_ENUMERATOR(ehash, 0, 0);
-    rb_secure(4);
-    result = rb_hash_new();
-    env = GET_ENVIRON(environ);
-    while (*env) {
-	char *s = strchr(*env, '=');
-	if (s) {
-	    VALUE k = env_str_new(*env, s-*env);
-	    VALUE v = env_str_new2(s+1);
-	    VALUE v2 = rb_yield_values(2, k, v);
-	    RETURN_IF_BROKEN();
-	    if (RTEST(v2)) {
-		rb_hash_aset(result, k, v);
-	    }
-	}
-	env++;
-    }
-    FREE_ENVIRON(environ);
-
-    return result;
-}
-
-static VALUE
-rb_env_clear_imp(VALUE rcv, SEL sel)
-{
-    VALUE keys;
-    long i;
-
-    keys = env_keys(Qnil, 0);	/* rb_secure(4); */
-    for (i=0; i<RARRAY_LEN(keys); i++) {
-	VALUE val = rb_f_getenv(Qnil, 0, RARRAY_AT(keys, i));
-	if (!NIL_P(val)) {
-	    env_delete(Qnil, RARRAY_AT(keys, i));
-	}
-    }
-    return envtbl;
-}
-
-VALUE
-rb_env_clear(void)
-{
-    return rb_env_clear_imp(Qnil, 0);
-}
-
-static VALUE
-env_to_s(VALUE rcv, SEL sel)
-{
-    return rb_usascii_str_new2("ENV");
-}
-
-static VALUE
-env_inspect(VALUE rcv, SEL sel)
-{
-    char **env;
-    VALUE str, i;
-
-    rb_secure(4);
-    str = rb_str_buf_new2("{");
-    env = GET_ENVIRON(environ);
-    while (*env) {
-	char *s = strchr(*env, '=');
-
-	if (env != environ) {
-	    rb_str_buf_cat2(str, ", ");
-	}
-	if (s) {
-	    rb_str_buf_cat2(str, "\"");
-	    rb_str_buf_cat(str, *env, s-*env);
-	    rb_str_buf_cat2(str, "\"=>");
-	    i = rb_inspect(rb_str_new2(s+1));
-	    rb_str_buf_append(str, i);
-	}
-	env++;
-    }
-    FREE_ENVIRON(environ);
-    rb_str_buf_cat2(str, "}");
-    OBJ_TAINT(str);
-
-    return str;
-}
-
-static VALUE
-env_to_a(VALUE rcv, SEL sel)
-{
-    char **env;
-    VALUE ary;
-
-    rb_secure(4);
-    ary = rb_ary_new();
-    env = GET_ENVIRON(environ);
-    while (*env) {
-	char *s = strchr(*env, '=');
-	if (s) {
-	    rb_ary_push(ary, rb_assoc_new(env_str_new(*env, s-*env),
-					  env_str_new2(s+1)));
-	}
-	env++;
-    }
-    FREE_ENVIRON(environ);
-    return ary;
-}
-
-static VALUE
-env_none(VALUE rcv, SEL sel)
-{
-    return Qnil;
-}
-
-static VALUE
-env_size(VALUE rcv, SEL sel)
-{
-    int i;
-    char **env;
-
-    rb_secure(4);
-    env = GET_ENVIRON(environ);
-    for(i=0; env[i]; i++)
-	;
-    FREE_ENVIRON(environ);
-    return INT2FIX(i);
-}
-
-static VALUE
-env_empty_p(VALUE rcv, SEL sel)
-{
-    char **env;
-
-    rb_secure(4);
-    env = GET_ENVIRON(environ);
-    if (env[0] == 0) {
-	FREE_ENVIRON(environ);
-	return Qtrue;
-    }
-    FREE_ENVIRON(environ);
-    return Qfalse;
-}
-
-static VALUE
-env_has_key(VALUE env, SEL sel, VALUE key)
-{
-    char *s;
-
-    rb_secure(4);
-    s = StringValuePtr(key);
-    if (strlen(s) != RSTRING_LEN(key))
-	rb_raise(rb_eArgError, "bad environment variable name");
-    if (getenv(s)) return Qtrue;
-    return Qfalse;
-}
-
-static VALUE
-env_assoc(VALUE env, SEL sel, VALUE key)
-{
-    char *s, *e;
-
-    rb_secure(4);
-    s = StringValuePtr(key);
-    if (strlen(s) != RSTRING_LEN(key))
-	rb_raise(rb_eArgError, "bad environment variable name");
-    e = getenv(s);
-    if (e) return rb_assoc_new(key, rb_tainted_str_new2(e));
-    return Qnil;
-}
-
-static VALUE
-env_has_value(VALUE dmy, SEL sel, VALUE obj)
-{
-    char **env;
-
-    rb_secure(4);
-    obj = rb_check_string_type(obj);
-    if (NIL_P(obj)) return Qnil;
-    env = GET_ENVIRON(environ);
-    while (*env) {
-	char *s = strchr(*env, '=');
-	if (s++) {
-	    long len = strlen(s);
-	    if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) {
-		FREE_ENVIRON(environ);
-		return Qtrue;
-	    }
-	}
-	env++;
-    }
-    FREE_ENVIRON(environ);
-    return Qfalse;
-}
-
-static VALUE
-env_rassoc(VALUE dmy, VALUE obj)
-{
-    char **env;
-
-    rb_secure(4);
-    obj = rb_check_string_type(obj);
-    if (NIL_P(obj)) return Qnil;
-    env = GET_ENVIRON(environ);
-    while (*env) {
-	char *s = strchr(*env, '=');
-	if (s++) {
-	    long len = strlen(s);
-	    if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) {
-		VALUE result = rb_assoc_new(rb_tainted_str_new(*env, s-*env-1), obj);
-		FREE_ENVIRON(environ);
-		return result;
-	    }
-	}
-	env++;
-    }
-    FREE_ENVIRON(environ);
-    return Qnil;
-}
-
-static VALUE
-env_key(VALUE dmy, SEL sel, VALUE value)
-{
-    char **env;
-    VALUE str;
-
-    rb_secure(4);
-    StringValue(value);
-    env = GET_ENVIRON(environ);
-    while (*env) {
-	char *s = strchr(*env, '=');
-	if (s++) {
-	    long len = strlen(s);
-	    if (RSTRING_LEN(value) == len && strncmp(s, RSTRING_PTR(value), len) == 0) {
-		str = env_str_new(*env, s-*env-1);
-		FREE_ENVIRON(environ);
-		return str;
-	    }
-	}
-	env++;
-    }
-    FREE_ENVIRON(environ);
-    return Qnil;
-}
-
-static VALUE
-env_index(VALUE dmy, SEL sel, VALUE value)
-{
-    rb_warn("ENV.index is deprecated; use ENV.key");
-    return env_key(dmy, 0, value);
-}
-
-static VALUE
-env_to_hash(VALUE rcv, SEL sel)
-{
-    char **env;
-    VALUE hash;
-
-    rb_secure(4);
-    hash = rb_hash_new();
-    env = GET_ENVIRON(environ);
-    while (*env) {
-	char *s = strchr(*env, '=');
-	if (s) {
-	    rb_hash_aset(hash, env_str_new(*env, s-*env),
-			       env_str_new2(s+1));
-	}
-	env++;
-    }
-    FREE_ENVIRON(environ);
-    return hash;
-}
-
-static VALUE
-env_reject(VALUE rcv, SEL sel)
-{
-    return rhash_delete_if(env_to_hash(Qnil, 0), 0);
-}
-
-static VALUE
-env_shift(VALUE rcv, SEL sel)
-{
-    char **env;
-
-    rb_secure(4);
-    env = GET_ENVIRON(environ);
-    if (*env) {
-	char *s = strchr(*env, '=');
-	if (s) {
-	    VALUE key = env_str_new(*env, s-*env);
-	    VALUE val = env_str_new2(getenv(RSTRING_PTR(key)));
-	    env_delete(Qnil, key);
-	    return rb_assoc_new(key, val);
-	}
-    }
-    FREE_ENVIRON(environ);
-    return Qnil;
-}
-
-static VALUE
-env_invert(VALUE rcv, SEL sel)
-{
-    return rhash_invert(env_to_hash(Qnil, 0), 0);
-}
-
-static int
-env_replace_i(VALUE key, VALUE val, VALUE keys)
-{
-    if (key != Qundef) {
-	env_aset(Qnil, 0, key, val);
-	if (rb_ary_includes(keys, key)) {
-	    rb_ary_delete(keys, key);
-	}
-    }
-    return ST_CONTINUE;
-}
-
-static VALUE
-env_replace(VALUE env, SEL sel, VALUE hash)
-{
-    volatile VALUE keys;
-    long i;
-
-    keys = env_keys(Qnil, 0);	/* rb_secure(4); */
-    if (env == hash) return env;
-    hash = to_hash(hash);
-    rb_hash_foreach(hash, env_replace_i, keys);
-
-    for (i=0; i<RARRAY_LEN(keys); i++) {
-	env_delete(env, RARRAY_AT(keys, i));
-    }
-    return env;
-}
-
-static int
-env_update_i(VALUE key, VALUE val)
-{
-    if (key != Qundef) {
-	if (rb_block_given_p()) {
-	    val = rb_yield_values(3, key, rb_f_getenv(Qnil, 0, key), val);
-	    RETURN_IF_BROKEN();
-	}
-	env_aset(Qnil, 0, key, val);
-    }
-    return ST_CONTINUE;
-}
-
-static VALUE
-env_update(VALUE env, SEL sel, VALUE hash)
-{
-    rb_secure(4);
-    if (env == hash) return env;
-    hash = to_hash(hash);
-    rb_hash_foreach(hash, env_update_i, 0);
-    return env;
-}
-
 bool
 rb_objc_hash_is_pure(VALUE hash)
 {
@@ -2756,50 +2050,4 @@
 	(IMP)imp_rhash_keyenum_allObjects);
     rb_objc_install_method2((Class)rb_cRubyHashKeyEnumerator, "nextObject",
 	(IMP)imp_rhash_keyenum_nextObject);
-
-    origenviron = environ;
-    envtbl = rb_obj_alloc(rb_cObject);
-    rb_extend_object(envtbl, rb_mEnumerable);
-
-    rb_objc_define_method(*(VALUE *)envtbl, "[]", rb_f_getenv, 1);
-    rb_objc_define_method(*(VALUE *)envtbl, "fetch", env_fetch, -1);
-    rb_objc_define_method(*(VALUE *)envtbl, "[]=", env_aset, 2);
-    rb_objc_define_method(*(VALUE *)envtbl, "store", env_aset, 2);
-    rb_objc_define_method(*(VALUE *)envtbl, "each", env_each_pair, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "each_pair", env_each_pair, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "each_key", env_each_key, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "each_value", env_each_value, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "delete", env_delete_m, 1);
-    rb_objc_define_method(*(VALUE *)envtbl, "delete_if", env_delete_if, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "clear", rb_env_clear_imp, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "reject", env_reject, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "reject!", env_reject_bang, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "select", env_select, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "shift", env_shift, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "invert", env_invert, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "replace", env_replace, 1);
-    rb_objc_define_method(*(VALUE *)envtbl, "update", env_update, 1);
-    rb_objc_define_method(*(VALUE *)envtbl, "inspect", env_inspect, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "rehash", env_none, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "to_a", env_to_a, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "to_s", env_to_s, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "key", env_key, 1);
-    rb_objc_define_method(*(VALUE *)envtbl, "index", env_index, 1);
-    rb_objc_define_method(*(VALUE *)envtbl, "size", env_size, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "length", env_size, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "empty?", env_empty_p, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "keys", env_keys, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "values", env_values, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "values_at", env_values_at, -1);
-    rb_objc_define_method(*(VALUE *)envtbl, "include?", env_has_key, 1);
-    rb_objc_define_method(*(VALUE *)envtbl, "member?", env_has_key, 1);
-    rb_objc_define_method(*(VALUE *)envtbl, "has_key?", env_has_key, 1);
-    rb_objc_define_method(*(VALUE *)envtbl, "has_value?", env_has_value, 1);
-    rb_objc_define_method(*(VALUE *)envtbl, "key?", env_has_key, 1);
-    rb_objc_define_method(*(VALUE *)envtbl, "value?", env_has_value, 1);
-    rb_objc_define_method(*(VALUE *)envtbl, "to_hash", env_to_hash, 0);
-    rb_objc_define_method(*(VALUE *)envtbl, "assoc", env_assoc, 1);
-    rb_objc_define_method(*(VALUE *)envtbl, "rassoc", env_rassoc, 1);
-
-    rb_define_global_const("ENV", envtbl);
 }

Modified: MacRuby/trunk/rakelib/builder/builder.rb
===================================================================
--- MacRuby/trunk/rakelib/builder/builder.rb	2010-02-04 02:10:07 UTC (rev 3429)
+++ MacRuby/trunk/rakelib/builder/builder.rb	2010-02-04 05:29:57 UTC (rev 3430)
@@ -2,7 +2,7 @@
 
 OBJS = %w{
   array bignum class compar complex enum enumerator error eval file load proc 
-  gc hash inits io math numeric object pack parse prec dir process
+  gc hash env inits io math numeric object pack parse prec dir process
   random range rational re onig/regcomp onig/regext onig/regposix onig/regenc
   onig/reggnu onig/regsyntax onig/regerror onig/regparse onig/regtrav
   onig/regexec onig/regposerr onig/regversion onig/enc/ascii onig/enc/unicode
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100203/5449ce21/attachment-0001.html>


More information about the macruby-changes mailing list