00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "ruby/ruby.h"
00015 #include "ruby/st.h"
00016 #include "ruby/util.h"
00017 #include "ruby/encoding.h"
00018 #include <errno.h>
00019
00020 #ifdef __APPLE__
00021 #include <crt_externs.h>
00022 #endif
00023
00024 static VALUE rb_hash_s_try_convert(VALUE, VALUE);
00025
00026 #define HASH_DELETED FL_USER1
00027 #define HASH_PROC_DEFAULT FL_USER2
00028
00029 VALUE
00030 rb_hash_freeze(VALUE hash)
00031 {
00032 return rb_obj_freeze(hash);
00033 }
00034
00035 VALUE rb_cHash;
00036
00037 static VALUE envtbl;
00038 static ID id_hash, id_yield, id_default;
00039
00040 static int
00041 rb_any_cmp(VALUE a, VALUE b)
00042 {
00043 if (a == b) return 0;
00044 if (FIXNUM_P(a) && FIXNUM_P(b)) {
00045 return a != b;
00046 }
00047 if (TYPE(a) == T_STRING && RBASIC(a)->klass == rb_cString &&
00048 TYPE(b) == T_STRING && RBASIC(b)->klass == rb_cString) {
00049 return rb_str_hash_cmp(a, b);
00050 }
00051 if (a == Qundef || b == Qundef) return -1;
00052 if (SYMBOL_P(a) && SYMBOL_P(b)) {
00053 return a != b;
00054 }
00055
00056 return !rb_eql(a, b);
00057 }
00058
00059 VALUE
00060 rb_hash(VALUE obj)
00061 {
00062 VALUE hval = rb_funcall(obj, id_hash, 0);
00063 retry:
00064 switch (TYPE(hval)) {
00065 case T_FIXNUM:
00066 return hval;
00067
00068 case T_BIGNUM:
00069 return LONG2FIX(((long*)(RBIGNUM_DIGITS(hval)))[0]);
00070
00071 default:
00072 hval = rb_to_int(hval);
00073 goto retry;
00074 }
00075 }
00076
00077 static st_index_t
00078 rb_any_hash(VALUE a)
00079 {
00080 VALUE hval;
00081 st_index_t hnum;
00082
00083 switch (TYPE(a)) {
00084 case T_FIXNUM:
00085 case T_SYMBOL:
00086 case T_NIL:
00087 case T_FALSE:
00088 case T_TRUE:
00089 hnum = rb_hash_end(rb_hash_start((unsigned int)a));
00090 break;
00091
00092 case T_STRING:
00093 hnum = rb_str_hash(a);
00094 break;
00095
00096 default:
00097 hval = rb_hash(a);
00098 hnum = FIX2LONG(hval);
00099 }
00100 hnum <<= 1;
00101 return (st_index_t)RSHIFT(hnum, 1);
00102 }
00103
00104 static const struct st_hash_type objhash = {
00105 rb_any_cmp,
00106 rb_any_hash,
00107 };
00108
00109 static const struct st_hash_type identhash = {
00110 st_numcmp,
00111 st_numhash,
00112 };
00113
00114 typedef int st_foreach_func(st_data_t, st_data_t, st_data_t);
00115
00116 struct foreach_safe_arg {
00117 st_table *tbl;
00118 st_foreach_func *func;
00119 st_data_t arg;
00120 };
00121
00122 static int
00123 foreach_safe_i(st_data_t key, st_data_t value, struct foreach_safe_arg *arg)
00124 {
00125 int status;
00126
00127 if (key == Qundef) return ST_CONTINUE;
00128 status = (*arg->func)(key, value, arg->arg);
00129 if (status == ST_CONTINUE) {
00130 return ST_CHECK;
00131 }
00132 return status;
00133 }
00134
00135 void
00136 st_foreach_safe(st_table *table, int (*func)(ANYARGS), st_data_t a)
00137 {
00138 struct foreach_safe_arg arg;
00139
00140 arg.tbl = table;
00141 arg.func = (st_foreach_func *)func;
00142 arg.arg = a;
00143 if (st_foreach(table, foreach_safe_i, (st_data_t)&arg)) {
00144 rb_raise(rb_eRuntimeError, "hash modified during iteration");
00145 }
00146 }
00147
00148 typedef int rb_foreach_func(VALUE, VALUE, VALUE);
00149
00150 struct hash_foreach_arg {
00151 VALUE hash;
00152 rb_foreach_func *func;
00153 VALUE arg;
00154 };
00155
00156 static int
00157 hash_foreach_iter(st_data_t key, st_data_t value, struct hash_foreach_arg *arg)
00158 {
00159 int status;
00160 st_table *tbl;
00161
00162 tbl = RHASH(arg->hash)->ntbl;
00163 if ((VALUE)key == Qundef) return ST_CONTINUE;
00164 status = (*arg->func)((VALUE)key, (VALUE)value, arg->arg);
00165 if (RHASH(arg->hash)->ntbl != tbl) {
00166 rb_raise(rb_eRuntimeError, "rehash occurred during iteration");
00167 }
00168 switch (status) {
00169 case ST_DELETE:
00170 st_delete_safe(tbl, &key, 0, Qundef);
00171 FL_SET(arg->hash, HASH_DELETED);
00172 case ST_CONTINUE:
00173 break;
00174 case ST_STOP:
00175 return ST_STOP;
00176 }
00177 return ST_CHECK;
00178 }
00179
00180 static VALUE
00181 hash_foreach_ensure(VALUE hash)
00182 {
00183 RHASH(hash)->iter_lev--;
00184
00185 if (RHASH(hash)->iter_lev == 0) {
00186 if (FL_TEST(hash, HASH_DELETED)) {
00187 st_cleanup_safe(RHASH(hash)->ntbl, Qundef);
00188 FL_UNSET(hash, HASH_DELETED);
00189 }
00190 }
00191 return 0;
00192 }
00193
00194 static VALUE
00195 hash_foreach_call(struct hash_foreach_arg *arg)
00196 {
00197 if (st_foreach(RHASH(arg->hash)->ntbl, hash_foreach_iter, (st_data_t)arg)) {
00198 rb_raise(rb_eRuntimeError, "hash modified during iteration");
00199 }
00200 return Qnil;
00201 }
00202
00203 void
00204 rb_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg)
00205 {
00206 struct hash_foreach_arg arg;
00207
00208 if (!RHASH(hash)->ntbl)
00209 return;
00210 RHASH(hash)->iter_lev++;
00211 arg.hash = hash;
00212 arg.func = (rb_foreach_func *)func;
00213 arg.arg = farg;
00214 rb_ensure(hash_foreach_call, (VALUE)&arg, hash_foreach_ensure, hash);
00215 }
00216
00217 static VALUE
00218 hash_alloc(VALUE klass)
00219 {
00220 NEWOBJ(hash, struct RHash);
00221 OBJSETUP(hash, klass, T_HASH);
00222
00223 RHASH_IFNONE(hash) = Qnil;
00224
00225 return (VALUE)hash;
00226 }
00227
00228 VALUE
00229 rb_hash_new(void)
00230 {
00231 return hash_alloc(rb_cHash);
00232 }
00233
00234 VALUE
00235 rb_hash_dup(VALUE hash)
00236 {
00237 NEWOBJ(ret, struct RHash);
00238 DUPSETUP(ret, hash);
00239
00240 if (!RHASH_EMPTY_P(hash))
00241 ret->ntbl = st_copy(RHASH(hash)->ntbl);
00242 if (FL_TEST(hash, HASH_PROC_DEFAULT)) {
00243 FL_SET(ret, HASH_PROC_DEFAULT);
00244 }
00245 RHASH_IFNONE(ret) = RHASH_IFNONE(hash);
00246 return (VALUE)ret;
00247 }
00248
00249 static void
00250 rb_hash_modify_check(VALUE hash)
00251 {
00252 rb_check_frozen(hash);
00253 if (!OBJ_UNTRUSTED(hash) && rb_safe_level() >= 4)
00254 rb_raise(rb_eSecurityError, "Insecure: can't modify hash");
00255 }
00256
00257 struct st_table *
00258 rb_hash_tbl(VALUE hash)
00259 {
00260 if (!RHASH(hash)->ntbl) {
00261 RHASH(hash)->ntbl = st_init_table(&objhash);
00262 }
00263 return RHASH(hash)->ntbl;
00264 }
00265
00266 static void
00267 rb_hash_modify(VALUE hash)
00268 {
00269 rb_hash_modify_check(hash);
00270 rb_hash_tbl(hash);
00271 }
00272
00273 static void
00274 hash_update(VALUE hash, VALUE key)
00275 {
00276 if (RHASH(hash)->iter_lev > 0 && !st_lookup(RHASH(hash)->ntbl, key, 0)) {
00277 rb_raise(rb_eRuntimeError, "can't add a new key into hash during iteration");
00278 }
00279 }
00280
00281 static void
00282 default_proc_arity_check(VALUE proc)
00283 {
00284 int n = rb_proc_arity(proc);
00285
00286 if (rb_proc_lambda_p(proc) && n != 2 && (n >= 0 || n < -3)) {
00287 if (n < 0) n = -n-1;
00288 rb_raise(rb_eTypeError, "default_proc takes two arguments (2 for %d)", n);
00289 }
00290 }
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327 static VALUE
00328 rb_hash_initialize(int argc, VALUE *argv, VALUE hash)
00329 {
00330 VALUE ifnone;
00331
00332 rb_hash_modify(hash);
00333 if (rb_block_given_p()) {
00334 if (argc > 0) {
00335 rb_raise(rb_eArgError, "wrong number of arguments");
00336 }
00337 ifnone = rb_block_proc();
00338 default_proc_arity_check(ifnone);
00339 RHASH_IFNONE(hash) = ifnone;
00340 FL_SET(hash, HASH_PROC_DEFAULT);
00341 }
00342 else {
00343 rb_scan_args(argc, argv, "01", &ifnone);
00344 RHASH_IFNONE(hash) = ifnone;
00345 }
00346
00347 return hash;
00348 }
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367 static VALUE
00368 rb_hash_s_create(int argc, VALUE *argv, VALUE klass)
00369 {
00370 VALUE hash, tmp;
00371 int i;
00372
00373 if (argc == 1) {
00374 tmp = rb_hash_s_try_convert(Qnil, argv[0]);
00375 if (!NIL_P(tmp)) {
00376 hash = hash_alloc(klass);
00377 if (RHASH(tmp)->ntbl) {
00378 RHASH(hash)->ntbl = st_copy(RHASH(tmp)->ntbl);
00379 }
00380 return hash;
00381 }
00382
00383 tmp = rb_check_array_type(argv[0]);
00384 if (!NIL_P(tmp)) {
00385 long i;
00386
00387 hash = hash_alloc(klass);
00388 for (i = 0; i < RARRAY_LEN(tmp); ++i) {
00389 VALUE v = rb_check_array_type(RARRAY_PTR(tmp)[i]);
00390 VALUE key, val = Qnil;
00391
00392 if (NIL_P(v)) continue;
00393 switch (RARRAY_LEN(v)) {
00394 case 2:
00395 val = RARRAY_PTR(v)[1];
00396 case 1:
00397 key = RARRAY_PTR(v)[0];
00398 rb_hash_aset(hash, key, val);
00399 }
00400 }
00401 return hash;
00402 }
00403 }
00404 if (argc % 2 != 0) {
00405 rb_raise(rb_eArgError, "odd number of arguments for Hash");
00406 }
00407
00408 hash = hash_alloc(klass);
00409 for (i=0; i<argc; i+=2) {
00410 rb_hash_aset(hash, argv[i], argv[i + 1]);
00411 }
00412
00413 return hash;
00414 }
00415
00416 static VALUE
00417 to_hash(VALUE hash)
00418 {
00419 return rb_convert_type(hash, T_HASH, "Hash", "to_hash");
00420 }
00421
00422 VALUE
00423 rb_check_hash_type(VALUE hash)
00424 {
00425 return rb_check_convert_type(hash, T_HASH, "Hash", "to_hash");
00426 }
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439 static VALUE
00440 rb_hash_s_try_convert(VALUE dummy, VALUE hash)
00441 {
00442 return rb_check_hash_type(hash);
00443 }
00444
00445 static int
00446 rb_hash_rehash_i(VALUE key, VALUE value, VALUE arg)
00447 {
00448 st_table *tbl = (st_table *)arg;
00449
00450 if (key != Qundef) st_insert(tbl, key, value);
00451 return ST_CONTINUE;
00452 }
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 static VALUE
00475 rb_hash_rehash(VALUE hash)
00476 {
00477 st_table *tbl;
00478
00479 if (RHASH(hash)->iter_lev > 0) {
00480 rb_raise(rb_eRuntimeError, "rehash during iteration");
00481 }
00482 rb_hash_modify_check(hash);
00483 if (!RHASH(hash)->ntbl)
00484 return hash;
00485 tbl = st_init_table_with_size(RHASH(hash)->ntbl->type, RHASH(hash)->ntbl->num_entries);
00486 rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tbl);
00487 st_free_table(RHASH(hash)->ntbl);
00488 RHASH(hash)->ntbl = tbl;
00489
00490 return hash;
00491 }
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507 VALUE
00508 rb_hash_aref(VALUE hash, VALUE key)
00509 {
00510 st_data_t val;
00511
00512 if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) {
00513 if (!FL_TEST(hash, HASH_PROC_DEFAULT) &&
00514 rb_method_basic_definition_p(CLASS_OF(hash), id_default)) {
00515 return RHASH_IFNONE(hash);
00516 }
00517 else {
00518 return rb_funcall(hash, id_default, 1, key);
00519 }
00520 }
00521 return (VALUE)val;
00522 }
00523
00524 VALUE
00525 rb_hash_lookup2(VALUE hash, VALUE key, VALUE def)
00526 {
00527 st_data_t val;
00528
00529 if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) {
00530 return def;
00531 }
00532 return (VALUE)val;
00533 }
00534
00535 VALUE
00536 rb_hash_lookup(VALUE hash, VALUE key)
00537 {
00538 return rb_hash_lookup2(hash, key, Qnil);
00539 }
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570 static VALUE
00571 rb_hash_fetch_m(int argc, VALUE *argv, VALUE hash)
00572 {
00573 VALUE key, if_none;
00574 st_data_t val;
00575 long block_given;
00576
00577 rb_scan_args(argc, argv, "11", &key, &if_none);
00578
00579 block_given = rb_block_given_p();
00580 if (block_given && argc == 2) {
00581 rb_warn("block supersedes default value argument");
00582 }
00583 if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) {
00584 if (block_given) return rb_yield(key);
00585 if (argc == 1) {
00586 volatile VALUE desc = rb_protect(rb_inspect, key, 0);
00587 if (NIL_P(desc)) {
00588 desc = rb_any_to_s(key);
00589 }
00590 desc = rb_str_ellipsize(desc, 65);
00591 rb_raise(rb_eKeyError, "key not found: %s", RSTRING_PTR(desc));
00592 }
00593 return if_none;
00594 }
00595 return (VALUE)val;
00596 }
00597
00598 VALUE
00599 rb_hash_fetch(VALUE hash, VALUE key)
00600 {
00601 return rb_hash_fetch_m(1, &key, hash);
00602 }
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625 static VALUE
00626 rb_hash_default(int argc, VALUE *argv, VALUE hash)
00627 {
00628 VALUE key, ifnone;
00629
00630 rb_scan_args(argc, argv, "01", &key);
00631 ifnone = RHASH_IFNONE(hash);
00632 if (FL_TEST(hash, HASH_PROC_DEFAULT)) {
00633 if (argc == 0) return Qnil;
00634 return rb_funcall(ifnone, id_yield, 2, hash, key);
00635 }
00636 return ifnone;
00637 }
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659 static VALUE
00660 rb_hash_set_default(VALUE hash, VALUE ifnone)
00661 {
00662 rb_hash_modify(hash);
00663 RHASH_IFNONE(hash) = ifnone;
00664 FL_UNSET(hash, HASH_PROC_DEFAULT);
00665 return ifnone;
00666 }
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683 static VALUE
00684 rb_hash_default_proc(VALUE hash)
00685 {
00686 if (FL_TEST(hash, HASH_PROC_DEFAULT)) {
00687 return RHASH_IFNONE(hash);
00688 }
00689 return Qnil;
00690 }
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705 static VALUE
00706 rb_hash_set_default_proc(VALUE hash, VALUE proc)
00707 {
00708 VALUE b;
00709
00710 rb_hash_modify(hash);
00711 b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc");
00712 if (NIL_P(b) || !rb_obj_is_proc(b)) {
00713 rb_raise(rb_eTypeError,
00714 "wrong default_proc type %s (expected Proc)",
00715 rb_obj_classname(proc));
00716 }
00717 proc = b;
00718 default_proc_arity_check(proc);
00719 RHASH_IFNONE(hash) = proc;
00720 FL_SET(hash, HASH_PROC_DEFAULT);
00721 return proc;
00722 }
00723
00724 static int
00725 key_i(VALUE key, VALUE value, VALUE arg)
00726 {
00727 VALUE *args = (VALUE *)arg;
00728
00729 if (rb_equal(value, args[0])) {
00730 args[1] = key;
00731 return ST_STOP;
00732 }
00733 return ST_CONTINUE;
00734 }
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750 static VALUE
00751 rb_hash_key(VALUE hash, VALUE value)
00752 {
00753 VALUE args[2];
00754
00755 args[0] = value;
00756 args[1] = Qnil;
00757
00758 rb_hash_foreach(hash, key_i, (VALUE)args);
00759
00760 return args[1];
00761 }
00762
00763
00764 static VALUE
00765 rb_hash_index(VALUE hash, VALUE value)
00766 {
00767 rb_warn("Hash#index is deprecated; use Hash#key");
00768 return rb_hash_key(hash, value);
00769 }
00770
00771 static VALUE
00772 rb_hash_delete_key(VALUE hash, VALUE key)
00773 {
00774 st_data_t ktmp = (st_data_t)key, val;
00775
00776 if (!RHASH(hash)->ntbl)
00777 return Qundef;
00778 if (RHASH(hash)->iter_lev > 0) {
00779 if (st_delete_safe(RHASH(hash)->ntbl, &ktmp, &val, Qundef)) {
00780 FL_SET(hash, HASH_DELETED);
00781 return (VALUE)val;
00782 }
00783 }
00784 else if (st_delete(RHASH(hash)->ntbl, &ktmp, &val))
00785 return (VALUE)val;
00786 return Qundef;
00787 }
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807 VALUE
00808 rb_hash_delete(VALUE hash, VALUE key)
00809 {
00810 VALUE val;
00811
00812 rb_hash_modify(hash);
00813 val = rb_hash_delete_key(hash, key);
00814 if (val != Qundef) return val;
00815 if (rb_block_given_p()) {
00816 return rb_yield(key);
00817 }
00818 return Qnil;
00819 }
00820
00821 struct shift_var {
00822 VALUE key;
00823 VALUE val;
00824 };
00825
00826 static int
00827 shift_i(VALUE key, VALUE value, VALUE arg)
00828 {
00829 struct shift_var *var = (struct shift_var *)arg;
00830
00831 if (key == Qundef) return ST_CONTINUE;
00832 if (var->key != Qundef) return ST_STOP;
00833 var->key = key;
00834 var->val = value;
00835 return ST_DELETE;
00836 }
00837
00838 static int
00839 shift_i_safe(VALUE key, VALUE value, VALUE arg)
00840 {
00841 struct shift_var *var = (struct shift_var *)arg;
00842
00843 if (key == Qundef) return ST_CONTINUE;
00844 var->key = key;
00845 var->val = value;
00846 return ST_STOP;
00847 }
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862 static VALUE
00863 rb_hash_shift(VALUE hash)
00864 {
00865 struct shift_var var;
00866
00867 rb_hash_modify(hash);
00868 var.key = Qundef;
00869 rb_hash_foreach(hash, RHASH(hash)->iter_lev > 0 ? shift_i_safe : shift_i,
00870 (VALUE)&var);
00871
00872 if (var.key != Qundef) {
00873 if (RHASH(hash)->iter_lev > 0) {
00874 rb_hash_delete_key(hash, var.key);
00875 }
00876 return rb_assoc_new(var.key, var.val);
00877 }
00878 else if (FL_TEST(hash, HASH_PROC_DEFAULT)) {
00879 return rb_funcall(RHASH_IFNONE(hash), id_yield, 2, hash, Qnil);
00880 }
00881 else {
00882 return RHASH_IFNONE(hash);
00883 }
00884 }
00885
00886 static int
00887 delete_if_i(VALUE key, VALUE value, VALUE hash)
00888 {
00889 if (key == Qundef) return ST_CONTINUE;
00890 if (RTEST(rb_yield_values(2, key, value))) {
00891 rb_hash_delete_key(hash, key);
00892 }
00893 return ST_CONTINUE;
00894 }
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911 VALUE
00912 rb_hash_delete_if(VALUE hash)
00913 {
00914 RETURN_ENUMERATOR(hash, 0, 0);
00915 rb_hash_modify(hash);
00916 rb_hash_foreach(hash, delete_if_i, hash);
00917 return hash;
00918 }
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929 VALUE
00930 rb_hash_reject_bang(VALUE hash)
00931 {
00932 st_index_t n;
00933
00934 RETURN_ENUMERATOR(hash, 0, 0);
00935 rb_hash_modify(hash);
00936 if (!RHASH(hash)->ntbl)
00937 return Qnil;
00938 n = RHASH(hash)->ntbl->num_entries;
00939 rb_hash_foreach(hash, delete_if_i, hash);
00940 if (n == RHASH(hash)->ntbl->num_entries) return Qnil;
00941 return hash;
00942 }
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955 static VALUE
00956 rb_hash_reject(VALUE hash)
00957 {
00958 return rb_hash_delete_if(rb_obj_dup(hash));
00959 }
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972 VALUE
00973 rb_hash_values_at(int argc, VALUE *argv, VALUE hash)
00974 {
00975 VALUE result = rb_ary_new2(argc);
00976 long i;
00977
00978 for (i=0; i<argc; i++) {
00979 rb_ary_push(result, rb_hash_aref(hash, argv[i]));
00980 }
00981 return result;
00982 }
00983
00984 static int
00985 select_i(VALUE key, VALUE value, VALUE result)
00986 {
00987 if (key == Qundef) return ST_CONTINUE;
00988 if (RTEST(rb_yield_values(2, key, value)))
00989 rb_hash_aset(result, key, value);
00990 return ST_CONTINUE;
00991 }
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007 VALUE
01008 rb_hash_select(VALUE hash)
01009 {
01010 VALUE result;
01011
01012 RETURN_ENUMERATOR(hash, 0, 0);
01013 result = rb_hash_new();
01014 rb_hash_foreach(hash, select_i, result);
01015 return result;
01016 }
01017
01018 static int
01019 keep_if_i(VALUE key, VALUE value, VALUE hash)
01020 {
01021 if (key == Qundef) return ST_CONTINUE;
01022 if (!RTEST(rb_yield_values(2, key, value))) {
01023 return ST_DELETE;
01024 }
01025 return ST_CONTINUE;
01026 }
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037 VALUE
01038 rb_hash_select_bang(VALUE hash)
01039 {
01040 st_index_t n;
01041
01042 RETURN_ENUMERATOR(hash, 0, 0);
01043 rb_hash_modify(hash);
01044 if (!RHASH(hash)->ntbl)
01045 return Qnil;
01046 n = RHASH(hash)->ntbl->num_entries;
01047 rb_hash_foreach(hash, keep_if_i, hash);
01048 if (n == RHASH(hash)->ntbl->num_entries) return Qnil;
01049 return hash;
01050 }
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064 VALUE
01065 rb_hash_keep_if(VALUE hash)
01066 {
01067 RETURN_ENUMERATOR(hash, 0, 0);
01068 rb_hash_modify(hash);
01069 rb_hash_foreach(hash, keep_if_i, hash);
01070 return hash;
01071 }
01072
01073 static int
01074 clear_i(VALUE key, VALUE value, VALUE dummy)
01075 {
01076 return ST_DELETE;
01077 }
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090 static VALUE
01091 rb_hash_clear(VALUE hash)
01092 {
01093 rb_hash_modify_check(hash);
01094 if (!RHASH(hash)->ntbl)
01095 return hash;
01096 if (RHASH(hash)->ntbl->num_entries > 0) {
01097 if (RHASH(hash)->iter_lev > 0)
01098 rb_hash_foreach(hash, clear_i, 0);
01099 else
01100 st_clear(RHASH(hash)->ntbl);
01101 }
01102
01103 return hash;
01104 }
01105
01106 static st_data_t
01107 copy_str_key(st_data_t str)
01108 {
01109 return (st_data_t)rb_str_new4((VALUE)str);
01110 }
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130 VALUE
01131 rb_hash_aset(VALUE hash, VALUE key, VALUE val)
01132 {
01133 rb_hash_modify(hash);
01134 hash_update(hash, key);
01135 if (RHASH(hash)->ntbl->type == &identhash || rb_obj_class(key) != rb_cString) {
01136 st_insert(RHASH(hash)->ntbl, key, val);
01137 }
01138 else {
01139 st_insert2(RHASH(hash)->ntbl, key, val, copy_str_key);
01140 }
01141 return val;
01142 }
01143
01144 static int
01145 replace_i(VALUE key, VALUE val, VALUE hash)
01146 {
01147 if (key != Qundef) {
01148 rb_hash_aset(hash, key, val);
01149 }
01150
01151 return ST_CONTINUE;
01152 }
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166 static VALUE
01167 rb_hash_replace(VALUE hash, VALUE hash2)
01168 {
01169 rb_hash_modify_check(hash);
01170 hash2 = to_hash(hash2);
01171 if (hash == hash2) return hash;
01172 rb_hash_clear(hash);
01173 if (RHASH(hash2)->ntbl) {
01174 rb_hash_tbl(hash);
01175 RHASH(hash)->ntbl->type = RHASH(hash2)->ntbl->type;
01176 }
01177 rb_hash_foreach(hash2, replace_i, hash);
01178 RHASH_IFNONE(hash) = RHASH_IFNONE(hash2);
01179 if (FL_TEST(hash2, HASH_PROC_DEFAULT)) {
01180 FL_SET(hash, HASH_PROC_DEFAULT);
01181 }
01182 else {
01183 FL_UNSET(hash, HASH_PROC_DEFAULT);
01184 }
01185
01186 return hash;
01187 }
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202 static VALUE
01203 rb_hash_size(VALUE hash)
01204 {
01205 if (!RHASH(hash)->ntbl)
01206 return INT2FIX(0);
01207 return INT2FIX(RHASH(hash)->ntbl->num_entries);
01208 }
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221 static VALUE
01222 rb_hash_empty_p(VALUE hash)
01223 {
01224 return RHASH_EMPTY_P(hash) ? Qtrue : Qfalse;
01225 }
01226
01227 static int
01228 each_value_i(VALUE key, VALUE value)
01229 {
01230 if (key == Qundef) return ST_CONTINUE;
01231 rb_yield(value);
01232 return ST_CONTINUE;
01233 }
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254 static VALUE
01255 rb_hash_each_value(VALUE hash)
01256 {
01257 RETURN_ENUMERATOR(hash, 0, 0);
01258 rb_hash_foreach(hash, each_value_i, 0);
01259 return hash;
01260 }
01261
01262 static int
01263 each_key_i(VALUE key, VALUE value)
01264 {
01265 if (key == Qundef) return ST_CONTINUE;
01266 rb_yield(key);
01267 return ST_CONTINUE;
01268 }
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288 static VALUE
01289 rb_hash_each_key(VALUE hash)
01290 {
01291 RETURN_ENUMERATOR(hash, 0, 0);
01292 rb_hash_foreach(hash, each_key_i, 0);
01293 return hash;
01294 }
01295
01296 static int
01297 each_pair_i(VALUE key, VALUE value)
01298 {
01299 if (key == Qundef) return ST_CONTINUE;
01300 rb_yield(rb_assoc_new(key, value));
01301 return ST_CONTINUE;
01302 }
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326 static VALUE
01327 rb_hash_each_pair(VALUE hash)
01328 {
01329 RETURN_ENUMERATOR(hash, 0, 0);
01330 rb_hash_foreach(hash, each_pair_i, 0);
01331 return hash;
01332 }
01333
01334 static int
01335 to_a_i(VALUE key, VALUE value, VALUE ary)
01336 {
01337 if (key == Qundef) return ST_CONTINUE;
01338 rb_ary_push(ary, rb_assoc_new(key, value));
01339 return ST_CONTINUE;
01340 }
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353 static VALUE
01354 rb_hash_to_a(VALUE hash)
01355 {
01356 VALUE ary;
01357
01358 ary = rb_ary_new();
01359 rb_hash_foreach(hash, to_a_i, ary);
01360 OBJ_INFECT(ary, hash);
01361
01362 return ary;
01363 }
01364
01365 static int
01366 inspect_i(VALUE key, VALUE value, VALUE str)
01367 {
01368 VALUE str2;
01369
01370 if (key == Qundef) return ST_CONTINUE;
01371 str2 = rb_inspect(key);
01372 if (RSTRING_LEN(str) > 1) {
01373 rb_str_cat2(str, ", ");
01374 }
01375 else {
01376 rb_enc_copy(str, str2);
01377 }
01378 rb_str_buf_append(str, str2);
01379 OBJ_INFECT(str, str2);
01380 rb_str_buf_cat2(str, "=>");
01381 str2 = rb_inspect(value);
01382 rb_str_buf_append(str, str2);
01383 OBJ_INFECT(str, str2);
01384
01385 return ST_CONTINUE;
01386 }
01387
01388 static VALUE
01389 inspect_hash(VALUE hash, VALUE dummy, int recur)
01390 {
01391 VALUE str;
01392
01393 if (recur) return rb_usascii_str_new2("{...}");
01394 str = rb_str_buf_new2("{");
01395 rb_hash_foreach(hash, inspect_i, str);
01396 rb_str_buf_cat2(str, "}");
01397 OBJ_INFECT(str, hash);
01398
01399 return str;
01400 }
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413 static VALUE
01414 rb_hash_inspect(VALUE hash)
01415 {
01416 if (RHASH_EMPTY_P(hash))
01417 return rb_usascii_str_new2("{}");
01418 return rb_exec_recursive(inspect_hash, hash, 0);
01419 }
01420
01421
01422
01423
01424
01425
01426
01427
01428 static VALUE
01429 rb_hash_to_hash(VALUE hash)
01430 {
01431 return hash;
01432 }
01433
01434 static int
01435 keys_i(VALUE key, VALUE value, VALUE ary)
01436 {
01437 if (key == Qundef) return ST_CONTINUE;
01438 rb_ary_push(ary, key);
01439 return ST_CONTINUE;
01440 }
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454 static VALUE
01455 rb_hash_keys(VALUE hash)
01456 {
01457 VALUE ary;
01458
01459 ary = rb_ary_new();
01460 rb_hash_foreach(hash, keys_i, ary);
01461
01462 return ary;
01463 }
01464
01465 static int
01466 values_i(VALUE key, VALUE value, VALUE ary)
01467 {
01468 if (key == Qundef) return ST_CONTINUE;
01469 rb_ary_push(ary, value);
01470 return ST_CONTINUE;
01471 }
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485 static VALUE
01486 rb_hash_values(VALUE hash)
01487 {
01488 VALUE ary;
01489
01490 ary = rb_ary_new();
01491 rb_hash_foreach(hash, values_i, ary);
01492
01493 return ary;
01494 }
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511 static VALUE
01512 rb_hash_has_key(VALUE hash, VALUE key)
01513 {
01514 if (!RHASH(hash)->ntbl)
01515 return Qfalse;
01516 if (st_lookup(RHASH(hash)->ntbl, key, 0)) {
01517 return Qtrue;
01518 }
01519 return Qfalse;
01520 }
01521
01522 static int
01523 rb_hash_search_value(VALUE key, VALUE value, VALUE arg)
01524 {
01525 VALUE *data = (VALUE *)arg;
01526
01527 if (key == Qundef) return ST_CONTINUE;
01528 if (rb_equal(value, data[1])) {
01529 data[0] = Qtrue;
01530 return ST_STOP;
01531 }
01532 return ST_CONTINUE;
01533 }
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548 static VALUE
01549 rb_hash_has_value(VALUE hash, VALUE val)
01550 {
01551 VALUE data[2];
01552
01553 data[0] = Qfalse;
01554 data[1] = val;
01555 rb_hash_foreach(hash, rb_hash_search_value, (VALUE)data);
01556 return data[0];
01557 }
01558
01559 struct equal_data {
01560 VALUE result;
01561 st_table *tbl;
01562 int eql;
01563 };
01564
01565 static int
01566 eql_i(VALUE key, VALUE val1, VALUE arg)
01567 {
01568 struct equal_data *data = (struct equal_data *)arg;
01569 st_data_t val2;
01570
01571 if (key == Qundef) return ST_CONTINUE;
01572 if (!st_lookup(data->tbl, key, &val2)) {
01573 data->result = Qfalse;
01574 return ST_STOP;
01575 }
01576 if (!(data->eql ? rb_eql(val1, (VALUE)val2) : (int)rb_equal(val1, (VALUE)val2))) {
01577 data->result = Qfalse;
01578 return ST_STOP;
01579 }
01580 return ST_CONTINUE;
01581 }
01582
01583 static VALUE
01584 recursive_eql(VALUE hash, VALUE dt, int recur)
01585 {
01586 struct equal_data *data;
01587
01588 if (recur) return Qtrue;
01589 data = (struct equal_data*)dt;
01590 data->result = Qtrue;
01591 rb_hash_foreach(hash, eql_i, dt);
01592
01593 return data->result;
01594 }
01595
01596 static VALUE
01597 hash_equal(VALUE hash1, VALUE hash2, int eql)
01598 {
01599 struct equal_data data;
01600
01601 if (hash1 == hash2) return Qtrue;
01602 if (TYPE(hash2) != T_HASH) {
01603 if (!rb_respond_to(hash2, rb_intern("to_hash"))) {
01604 return Qfalse;
01605 }
01606 if (eql)
01607 return rb_eql(hash2, hash1);
01608 else
01609 return rb_equal(hash2, hash1);
01610 }
01611 if (RHASH_SIZE(hash1) != RHASH_SIZE(hash2))
01612 return Qfalse;
01613 if (!RHASH(hash1)->ntbl || !RHASH(hash2)->ntbl)
01614 return Qtrue;
01615 if (RHASH(hash1)->ntbl->type != RHASH(hash2)->ntbl->type)
01616 return Qfalse;
01617 #if 0
01618 if (!(rb_equal(RHASH_IFNONE(hash1), RHASH_IFNONE(hash2)) &&
01619 FL_TEST(hash1, HASH_PROC_DEFAULT) == FL_TEST(hash2, HASH_PROC_DEFAULT)))
01620 return Qfalse;
01621 #endif
01622
01623 data.tbl = RHASH(hash2)->ntbl;
01624 data.eql = eql;
01625 return rb_exec_recursive_paired(recursive_eql, hash1, hash2, (VALUE)&data);
01626 }
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647 static VALUE
01648 rb_hash_equal(VALUE hash1, VALUE hash2)
01649 {
01650 return hash_equal(hash1, hash2, FALSE);
01651 }
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661 static VALUE
01662 rb_hash_eql(VALUE hash1, VALUE hash2)
01663 {
01664 return hash_equal(hash1, hash2, TRUE);
01665 }
01666
01667 static int
01668 hash_i(VALUE key, VALUE val, VALUE arg)
01669 {
01670 st_index_t *hval = (st_index_t *)arg;
01671 st_index_t hdata[2];
01672
01673 if (key == Qundef) return ST_CONTINUE;
01674 hdata[0] = rb_hash(key);
01675 hdata[1] = rb_hash(val);
01676 *hval ^= st_hash(hdata, sizeof(hdata), 0);
01677 return ST_CONTINUE;
01678 }
01679
01680 static VALUE
01681 recursive_hash(VALUE hash, VALUE dummy, int recur)
01682 {
01683 st_index_t hval;
01684
01685 if (!RHASH(hash)->ntbl)
01686 return LONG2FIX(0);
01687 hval = RHASH(hash)->ntbl->num_entries;
01688 if (!hval) return LONG2FIX(0);
01689 if (recur)
01690 hval = rb_hash_uint(rb_hash_start(rb_hash(rb_cHash)), hval);
01691 else
01692 rb_hash_foreach(hash, hash_i, (VALUE)&hval);
01693 hval = rb_hash_end(hval);
01694 return INT2FIX(hval);
01695 }
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705 static VALUE
01706 rb_hash_hash(VALUE hash)
01707 {
01708 return rb_exec_recursive_outer(recursive_hash, hash, 0);
01709 }
01710
01711 static int
01712 rb_hash_invert_i(VALUE key, VALUE value, VALUE hash)
01713 {
01714 if (key == Qundef) return ST_CONTINUE;
01715 rb_hash_aset(hash, value, key);
01716 return ST_CONTINUE;
01717 }
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731 static VALUE
01732 rb_hash_invert(VALUE hash)
01733 {
01734 VALUE h = rb_hash_new();
01735
01736 rb_hash_foreach(hash, rb_hash_invert_i, h);
01737 return h;
01738 }
01739
01740 static int
01741 rb_hash_update_i(VALUE key, VALUE value, VALUE hash)
01742 {
01743 if (key == Qundef) return ST_CONTINUE;
01744 hash_update(hash, key);
01745 st_insert(RHASH(hash)->ntbl, key, value);
01746 return ST_CONTINUE;
01747 }
01748
01749 static int
01750 rb_hash_update_block_i(VALUE key, VALUE value, VALUE hash)
01751 {
01752 if (key == Qundef) return ST_CONTINUE;
01753 if (rb_hash_has_key(hash, key)) {
01754 value = rb_yield_values(3, key, rb_hash_aref(hash, key), value);
01755 }
01756 hash_update(hash, key);
01757 st_insert(RHASH(hash)->ntbl, key, value);
01758 return ST_CONTINUE;
01759 }
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784 static VALUE
01785 rb_hash_update(VALUE hash1, VALUE hash2)
01786 {
01787 rb_hash_modify(hash1);
01788 hash2 = to_hash(hash2);
01789 if (rb_block_given_p()) {
01790 rb_hash_foreach(hash2, rb_hash_update_block_i, hash1);
01791 }
01792 else {
01793 rb_hash_foreach(hash2, rb_hash_update_i, hash1);
01794 }
01795 return hash1;
01796 }
01797
01798 struct update_arg {
01799 VALUE hash;
01800 rb_hash_update_func *func;
01801 };
01802
01803 static int
01804 rb_hash_update_func_i(VALUE key, VALUE value, VALUE arg0)
01805 {
01806 struct update_arg *arg = (struct update_arg *)arg0;
01807 VALUE hash = arg->hash;
01808
01809 if (key == Qundef) return ST_CONTINUE;
01810 if (rb_hash_has_key(hash, key)) {
01811 value = (*arg->func)(key, rb_hash_aref(hash, key), value);
01812 }
01813 hash_update(hash, key);
01814 st_insert(RHASH(hash)->ntbl, key, value);
01815 return ST_CONTINUE;
01816 }
01817
01818 VALUE
01819 rb_hash_update_by(VALUE hash1, VALUE hash2, rb_hash_update_func *func)
01820 {
01821 rb_hash_modify(hash1);
01822 hash2 = to_hash(hash2);
01823 if (func) {
01824 struct update_arg arg;
01825 arg.hash = hash1;
01826 arg.func = func;
01827 rb_hash_foreach(hash2, rb_hash_update_func_i, (VALUE)&arg);
01828 }
01829 else {
01830 rb_hash_foreach(hash2, rb_hash_update_i, hash1);
01831 }
01832 return hash1;
01833 }
01834
01835
01836
01837
01838
01839
01840
01841
01842
01843
01844
01845
01846
01847
01848
01849
01850
01851
01852
01853
01854
01855 static VALUE
01856 rb_hash_merge(VALUE hash1, VALUE hash2)
01857 {
01858 return rb_hash_update(rb_obj_dup(hash1), hash2);
01859 }
01860
01861 static int
01862 assoc_i(VALUE key, VALUE val, VALUE arg)
01863 {
01864 VALUE *args = (VALUE *)arg;
01865
01866 if (key == Qundef) return ST_CONTINUE;
01867 if (RTEST(rb_equal(args[0], key))) {
01868 args[1] = rb_assoc_new(key, val);
01869 return ST_STOP;
01870 }
01871 return ST_CONTINUE;
01872 }
01873
01874
01875
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885
01886
01887
01888 VALUE
01889 rb_hash_assoc(VALUE hash, VALUE obj)
01890 {
01891 VALUE args[2];
01892
01893 args[0] = obj;
01894 args[1] = Qnil;
01895 rb_hash_foreach(hash, assoc_i, (VALUE)args);
01896 return args[1];
01897 }
01898
01899 static int
01900 rassoc_i(VALUE key, VALUE val, VALUE arg)
01901 {
01902 VALUE *args = (VALUE *)arg;
01903
01904 if (key == Qundef) return ST_CONTINUE;
01905 if (RTEST(rb_equal(args[0], val))) {
01906 args[1] = rb_assoc_new(key, val);
01907 return ST_STOP;
01908 }
01909 return ST_CONTINUE;
01910 }
01911
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925 VALUE
01926 rb_hash_rassoc(VALUE hash, VALUE obj)
01927 {
01928 VALUE args[2];
01929
01930 args[0] = obj;
01931 args[1] = Qnil;
01932 rb_hash_foreach(hash, rassoc_i, (VALUE)args);
01933 return args[1];
01934 }
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944
01945
01946
01947
01948
01949
01950
01951
01952 static VALUE
01953 rb_hash_flatten(int argc, VALUE *argv, VALUE hash)
01954 {
01955 VALUE ary, tmp;
01956
01957 ary = rb_hash_to_a(hash);
01958 if (argc == 0) {
01959 argc = 1;
01960 tmp = INT2FIX(1);
01961 argv = &tmp;
01962 }
01963 rb_funcall2(ary, rb_intern("flatten!"), argc, argv);
01964 return ary;
01965 }
01966
01967
01968
01969
01970
01971
01972
01973
01974
01975
01976
01977
01978
01979
01980
01981
01982
01983 static VALUE
01984 rb_hash_compare_by_id(VALUE hash)
01985 {
01986 rb_hash_modify(hash);
01987 RHASH(hash)->ntbl->type = &identhash;
01988 rb_hash_rehash(hash);
01989 return hash;
01990 }
01991
01992
01993
01994
01995
01996
01997
01998
01999
02000
02001 static VALUE
02002 rb_hash_compare_by_id_p(VALUE hash)
02003 {
02004 if (!RHASH(hash)->ntbl)
02005 return Qfalse;
02006 if (RHASH(hash)->ntbl->type == &identhash) {
02007 return Qtrue;
02008 }
02009 return Qfalse;
02010 }
02011
02012 static int path_tainted = -1;
02013
02014 static char **origenviron;
02015 #ifdef _WIN32
02016 #define GET_ENVIRON(e) ((e) = rb_w32_get_environ())
02017 #define FREE_ENVIRON(e) rb_w32_free_environ(e)
02018 static char **my_environ;
02019 #undef environ
02020 #define environ my_environ
02021 #elif defined(__APPLE__)
02022 #undef environ
02023 #define environ (*_NSGetEnviron())
02024 #define GET_ENVIRON(e) (e)
02025 #define FREE_ENVIRON(e)
02026 #else
02027 extern char **environ;
02028 #define GET_ENVIRON(e) (e)
02029 #define FREE_ENVIRON(e)
02030 #endif
02031 #ifdef ENV_IGNORECASE
02032 #define ENVMATCH(s1, s2) (STRCASECMP((s1), (s2)) == 0)
02033 #define ENVNMATCH(s1, s2, n) (STRNCASECMP((s1), (s2), (n)) == 0)
02034 #else
02035 #define ENVMATCH(n1, n2) (strcmp((n1), (n2)) == 0)
02036 #define ENVNMATCH(s1, s2, n) (memcmp((s1), (s2), (n)) == 0)
02037 #endif
02038
02039 static VALUE
02040 env_str_new(const char *ptr, long len)
02041 {
02042 VALUE str = rb_locale_str_new(ptr, len);
02043
02044 rb_obj_freeze(str);
02045 return str;
02046 }
02047
02048 static VALUE
02049 env_str_new2(const char *ptr)
02050 {
02051 if (!ptr) return Qnil;
02052 return env_str_new(ptr, strlen(ptr));
02053 }
02054
02055 static VALUE
02056 env_delete(VALUE obj, VALUE name)
02057 {
02058 char *nam, *val;
02059
02060 rb_secure(4);
02061 SafeStringValue(name);
02062 nam = RSTRING_PTR(name);
02063 if (memchr(nam, '\0', RSTRING_LEN(name))) {
02064 rb_raise(rb_eArgError, "bad environment variable name");
02065 }
02066 val = getenv(nam);
02067 if (val) {
02068 VALUE value = env_str_new2(val);
02069
02070 ruby_setenv(nam, 0);
02071 if (ENVMATCH(nam, PATH_ENV)) {
02072 path_tainted = 0;
02073 }
02074 return value;
02075 }
02076 return Qnil;
02077 }
02078
02079
02080
02081
02082
02083
02084
02085
02086
02087
02088 static VALUE
02089 env_delete_m(VALUE obj, VALUE name)
02090 {
02091 VALUE val;
02092
02093 val = env_delete(obj, name);
02094 if (NIL_P(val) && rb_block_given_p()) rb_yield(name);
02095 return val;
02096 }
02097
02098 static int env_path_tainted(const char *);
02099
02100
02101
02102
02103
02104
02105
02106
02107 static VALUE
02108 rb_f_getenv(VALUE obj, VALUE name)
02109 {
02110 char *nam, *env;
02111
02112 rb_secure(4);
02113 SafeStringValue(name);
02114 nam = RSTRING_PTR(name);
02115 if (memchr(nam, '\0', RSTRING_LEN(name))) {
02116 rb_raise(rb_eArgError, "bad environment variable name");
02117 }
02118 env = getenv(nam);
02119 if (env) {
02120 if (ENVMATCH(nam, PATH_ENV) && !env_path_tainted(env)) {
02121 VALUE str = rb_filesystem_str_new_cstr(env);
02122
02123 rb_obj_freeze(str);
02124 return str;
02125 }
02126 return env_str_new2(env);
02127 }
02128 return Qnil;
02129 }
02130
02131
02132
02133
02134
02135
02136
02137
02138
02139
02140
02141
02142
02143
02144
02145 static VALUE
02146 env_fetch(int argc, VALUE *argv)
02147 {
02148 VALUE key, if_none;
02149 long block_given;
02150 char *nam, *env;
02151
02152 rb_secure(4);
02153 rb_scan_args(argc, argv, "11", &key, &if_none);
02154 block_given = rb_block_given_p();
02155 if (block_given && argc == 2) {
02156 rb_warn("block supersedes default value argument");
02157 }
02158 SafeStringValue(key);
02159 nam = RSTRING_PTR(key);
02160 if (memchr(nam, '\0', RSTRING_LEN(key))) {
02161 rb_raise(rb_eArgError, "bad environment variable name");
02162 }
02163 env = getenv(nam);
02164 if (!env) {
02165 if (block_given) return rb_yield(key);
02166 if (argc == 1) {
02167 rb_raise(rb_eKeyError, "key not found");
02168 }
02169 return if_none;
02170 }
02171 if (ENVMATCH(nam, PATH_ENV) && !env_path_tainted(env))
02172 return rb_filesystem_str_new_cstr(env);
02173 return env_str_new2(env);
02174 }
02175
02176 static void
02177 path_tainted_p(const char *path)
02178 {
02179 path_tainted = rb_path_check(path)?0:1;
02180 }
02181
02182 static int
02183 env_path_tainted(const char *path)
02184 {
02185 if (path_tainted < 0) {
02186 path_tainted_p(path);
02187 }
02188 return path_tainted;
02189 }
02190
02191 int
02192 rb_env_path_tainted(void)
02193 {
02194 if (path_tainted < 0) {
02195 path_tainted_p(getenv(PATH_ENV));
02196 }
02197 return path_tainted;
02198 }
02199
02200 #if defined(_WIN32) || (defined(HAVE_SETENV) && defined(HAVE_UNSETENV))
02201 #elif defined __sun__
02202 static int
02203 in_origenv(const char *str)
02204 {
02205 char **env;
02206 for (env = origenviron; *env; ++env) {
02207 if (*env == str) return 1;
02208 }
02209 return 0;
02210 }
02211 #else
02212 static int
02213 envix(const char *nam)
02214 {
02215 register int i, len = strlen(nam);
02216 char **env;
02217
02218 env = GET_ENVIRON(environ);
02219 for (i = 0; env[i]; i++) {
02220 if (ENVNMATCH(env[i],nam,len) && env[i][len] == '=')
02221 break;
02222 }
02223 FREE_ENVIRON(environ);
02224 return i;
02225 }
02226 #endif
02227
02228 #if defined(_WIN32)
02229 static size_t
02230 getenvsize(const char* p)
02231 {
02232 const char* porg = p;
02233 while (*p++) p += strlen(p) + 1;
02234 return p - porg + 1;
02235 }
02236 static size_t
02237 getenvblocksize()
02238 {
02239 return (rb_w32_osver() >= 5) ? 32767 : 5120;
02240 }
02241 #endif
02242
02243 void
02244 ruby_setenv(const char *name, const char *value)
02245 {
02246 #if defined(_WIN32)
02247 VALUE buf;
02248 int failed = 0;
02249 if (strchr(name, '=')) {
02250 fail:
02251 errno = EINVAL;
02252 rb_sys_fail("ruby_setenv");
02253 }
02254 if (value) {
02255 const char* p = GetEnvironmentStringsA();
02256 if (!p) goto fail;
02257 if (strlen(name) + 2 + strlen(value) + getenvsize(p) >= getenvblocksize()) {
02258 goto fail;
02259 }
02260 buf = rb_sprintf("%s=%s", name, value);
02261 }
02262 else {
02263 buf = rb_sprintf("%s=", name);
02264 }
02265 failed = putenv(RSTRING_PTR(buf));
02266
02267
02268 rb_str_resize(buf, 0);
02269 if (!value || !*value) {
02270
02271 if (!SetEnvironmentVariable(name, value) &&
02272 GetLastError() != ERROR_ENVVAR_NOT_FOUND) goto fail;
02273 }
02274 if (failed) goto fail;
02275 #elif defined(HAVE_SETENV) && defined(HAVE_UNSETENV)
02276 #undef setenv
02277 #undef unsetenv
02278 if (value) {
02279 if (setenv(name, value, 1))
02280 rb_sys_fail("setenv");
02281 } else {
02282 #ifdef VOID_UNSETENV
02283 unsetenv(name);
02284 #else
02285 if (unsetenv(name))
02286 rb_sys_fail("unsetenv");
02287 #endif
02288 }
02289 #elif defined __sun__
02290 size_t len;
02291 char **env_ptr, *str;
02292 if (strchr(name, '=')) {
02293 errno = EINVAL;
02294 rb_sys_fail("ruby_setenv");
02295 }
02296 len = strlen(name);
02297 for (env_ptr = GET_ENVIRON(environ); (str = *env_ptr) != 0; ++env_ptr) {
02298 if (!strncmp(str, name, len) && str[len] == '=') {
02299 if (!in_origenv(str)) free(str);
02300 while ((env_ptr[0] = env_ptr[1]) != 0) env_ptr++;
02301 break;
02302 }
02303 }
02304 if (value) {
02305 str = malloc(len += strlen(value) + 2);
02306 snprintf(str, len, "%s=%s", name, value);
02307 if (putenv(str))
02308 rb_sys_fail("putenv");
02309 }
02310 #else
02311 size_t len;
02312 int i;
02313 if (strchr(name, '=')) {
02314 errno = EINVAL;
02315 rb_sys_fail("ruby_setenv");
02316 }
02317 i=envix(name);
02318
02319 if (environ == origenviron) {
02320 int j;
02321 int max;
02322 char **tmpenv;
02323
02324 for (max = i; environ[max]; max++) ;
02325 tmpenv = ALLOC_N(char*, max+2);
02326 for (j=0; j<max; j++)
02327 tmpenv[j] = ruby_strdup(environ[j]);
02328 tmpenv[max] = 0;
02329 environ = tmpenv;
02330 }
02331 if (environ[i]) {
02332 char **envp = origenviron;
02333 while (*envp && *envp != environ[i]) envp++;
02334 if (!*envp)
02335 xfree(environ[i]);
02336 if (!value) {
02337 while (environ[i]) {
02338 environ[i] = environ[i+1];
02339 i++;
02340 }
02341 return;
02342 }
02343 }
02344 else {
02345 if (!value) return;
02346 REALLOC_N(environ, char*, i+2);
02347 environ[i+1] = 0;
02348 }
02349 len = strlen(name) + strlen(value) + 2;
02350 environ[i] = ALLOC_N(char, len);
02351 snprintf(environ[i],len,"%s=%s",name,value);
02352 #endif
02353 }
02354
02355 void
02356 ruby_unsetenv(const char *name)
02357 {
02358 ruby_setenv(name, 0);
02359 }
02360
02361
02362
02363
02364
02365
02366
02367
02368
02369
02370 static VALUE
02371 env_aset(VALUE obj, VALUE nm, VALUE val)
02372 {
02373 char *name, *value;
02374
02375 if (rb_safe_level() >= 4) {
02376 rb_raise(rb_eSecurityError, "can't change environment variable");
02377 }
02378
02379 if (NIL_P(val)) {
02380 env_delete(obj, nm);
02381 return Qnil;
02382 }
02383 StringValue(nm);
02384 StringValue(val);
02385 name = RSTRING_PTR(nm);
02386 value = RSTRING_PTR(val);
02387 if (memchr(name, '\0', RSTRING_LEN(nm)))
02388 rb_raise(rb_eArgError, "bad environment variable name");
02389 if (memchr(value, '\0', RSTRING_LEN(val)))
02390 rb_raise(rb_eArgError, "bad environment variable value");
02391
02392 ruby_setenv(name, value);
02393 if (ENVMATCH(name, PATH_ENV)) {
02394 if (OBJ_TAINTED(val)) {
02395
02396 path_tainted = 1;
02397 return val;
02398 }
02399 else {
02400 path_tainted_p(value);
02401 }
02402 }
02403 return val;
02404 }
02405
02406
02407
02408
02409
02410
02411
02412 static VALUE
02413 env_keys(void)
02414 {
02415 char **env;
02416 VALUE ary;
02417
02418 rb_secure(4);
02419 ary = rb_ary_new();
02420 env = GET_ENVIRON(environ);
02421 while (*env) {
02422 char *s = strchr(*env, '=');
02423 if (s) {
02424 rb_ary_push(ary, env_str_new(*env, s-*env));
02425 }
02426 env++;
02427 }
02428 FREE_ENVIRON(environ);
02429 return ary;
02430 }
02431
02432
02433
02434
02435
02436
02437
02438
02439
02440
02441 static VALUE
02442 env_each_key(VALUE ehash)
02443 {
02444 VALUE keys;
02445 long i;
02446
02447 RETURN_ENUMERATOR(ehash, 0, 0);
02448 keys = env_keys();
02449 for (i=0; i<RARRAY_LEN(keys); i++) {
02450 rb_yield(RARRAY_PTR(keys)[i]);
02451 }
02452 return ehash;
02453 }
02454
02455
02456
02457
02458
02459
02460
02461 static VALUE
02462 env_values(void)
02463 {
02464 VALUE ary;
02465 char **env;
02466
02467 rb_secure(4);
02468 ary = rb_ary_new();
02469 env = GET_ENVIRON(environ);
02470 while (*env) {
02471 char *s = strchr(*env, '=');
02472 if (s) {
02473 rb_ary_push(ary, env_str_new2(s+1));
02474 }
02475 env++;
02476 }
02477 FREE_ENVIRON(environ);
02478 return ary;
02479 }
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490 static VALUE
02491 env_each_value(VALUE ehash)
02492 {
02493 VALUE values;
02494 long i;
02495
02496 RETURN_ENUMERATOR(ehash, 0, 0);
02497 values = env_values();
02498 for (i=0; i<RARRAY_LEN(values); i++) {
02499 rb_yield(RARRAY_PTR(values)[i]);
02500 }
02501 return ehash;
02502 }
02503
02504
02505
02506
02507
02508
02509
02510
02511
02512
02513
02514
02515 static VALUE
02516 env_each_pair(VALUE ehash)
02517 {
02518 char **env;
02519 VALUE ary;
02520 long i;
02521
02522 RETURN_ENUMERATOR(ehash, 0, 0);
02523
02524 rb_secure(4);
02525 ary = rb_ary_new();
02526 env = GET_ENVIRON(environ);
02527 while (*env) {
02528 char *s = strchr(*env, '=');
02529 if (s) {
02530 rb_ary_push(ary, env_str_new(*env, s-*env));
02531 rb_ary_push(ary, env_str_new2(s+1));
02532 }
02533 env++;
02534 }
02535 FREE_ENVIRON(environ);
02536
02537 for (i=0; i<RARRAY_LEN(ary); i+=2) {
02538 rb_yield(rb_assoc_new(RARRAY_PTR(ary)[i], RARRAY_PTR(ary)[i+1]));
02539 }
02540 return ehash;
02541 }
02542
02543
02544
02545
02546
02547
02548
02549
02550
02551
02552 static VALUE
02553 env_reject_bang(VALUE ehash)
02554 {
02555 volatile VALUE keys;
02556 long i;
02557 int del = 0;
02558
02559 RETURN_ENUMERATOR(ehash, 0, 0);
02560 keys = env_keys();
02561 for (i=0; i<RARRAY_LEN(keys); i++) {
02562 VALUE val = rb_f_getenv(Qnil, RARRAY_PTR(keys)[i]);
02563 if (!NIL_P(val)) {
02564 if (RTEST(rb_yield_values(2, RARRAY_PTR(keys)[i], val))) {
02565 FL_UNSET(RARRAY_PTR(keys)[i], FL_TAINT);
02566 env_delete(Qnil, RARRAY_PTR(keys)[i]);
02567 del++;
02568 }
02569 }
02570 }
02571 if (del == 0) return Qnil;
02572 return envtbl;
02573 }
02574
02575
02576
02577
02578
02579
02580
02581
02582
02583
02584 static VALUE
02585 env_delete_if(VALUE ehash)
02586 {
02587 RETURN_ENUMERATOR(ehash, 0, 0);
02588 env_reject_bang(ehash);
02589 return envtbl;
02590 }
02591
02592
02593
02594
02595
02596
02597
02598
02599 static VALUE
02600 env_values_at(int argc, VALUE *argv)
02601 {
02602 VALUE result;
02603 long i;
02604
02605 rb_secure(4);
02606 result = rb_ary_new();
02607 for (i=0; i<argc; i++) {
02608 rb_ary_push(result, rb_f_getenv(Qnil, argv[i]));
02609 }
02610 return result;
02611 }
02612
02613
02614
02615
02616
02617
02618
02619
02620
02621
02622 static VALUE
02623 env_select(VALUE ehash)
02624 {
02625 VALUE result;
02626 char **env;
02627
02628 RETURN_ENUMERATOR(ehash, 0, 0);
02629 rb_secure(4);
02630 result = rb_hash_new();
02631 env = GET_ENVIRON(environ);
02632 while (*env) {
02633 char *s = strchr(*env, '=');
02634 if (s) {
02635 VALUE k = env_str_new(*env, s-*env);
02636 VALUE v = env_str_new2(s+1);
02637 if (RTEST(rb_yield_values(2, k, v))) {
02638 rb_hash_aset(result, k, v);
02639 }
02640 }
02641 env++;
02642 }
02643 FREE_ENVIRON(environ);
02644
02645 return result;
02646 }
02647
02648
02649
02650
02651
02652
02653
02654
02655 static VALUE
02656 env_select_bang(VALUE ehash)
02657 {
02658 volatile VALUE keys;
02659 long i;
02660 int del = 0;
02661
02662 RETURN_ENUMERATOR(ehash, 0, 0);
02663 keys = env_keys();
02664 for (i=0; i<RARRAY_LEN(keys); i++) {
02665 VALUE val = rb_f_getenv(Qnil, RARRAY_PTR(keys)[i]);
02666 if (!NIL_P(val)) {
02667 if (!RTEST(rb_yield_values(2, RARRAY_PTR(keys)[i], val))) {
02668 FL_UNSET(RARRAY_PTR(keys)[i], FL_TAINT);
02669 env_delete(Qnil, RARRAY_PTR(keys)[i]);
02670 del++;
02671 }
02672 }
02673 }
02674 if (del == 0) return Qnil;
02675 return envtbl;
02676 }
02677
02678
02679
02680
02681
02682
02683
02684
02685
02686
02687 static VALUE
02688 env_keep_if(VALUE ehash)
02689 {
02690 RETURN_ENUMERATOR(ehash, 0, 0);
02691 env_select_bang(ehash);
02692 return envtbl;
02693 }
02694
02695
02696
02697
02698
02699
02700
02701 VALUE
02702 rb_env_clear(void)
02703 {
02704 volatile VALUE keys;
02705 long i;
02706
02707 keys = env_keys();
02708 for (i=0; i<RARRAY_LEN(keys); i++) {
02709 VALUE val = rb_f_getenv(Qnil, RARRAY_PTR(keys)[i]);
02710 if (!NIL_P(val)) {
02711 env_delete(Qnil, RARRAY_PTR(keys)[i]);
02712 }
02713 }
02714 return envtbl;
02715 }
02716
02717
02718
02719
02720
02721
02722
02723 static VALUE
02724 env_to_s(void)
02725 {
02726 return rb_usascii_str_new2("ENV");
02727 }
02728
02729
02730
02731
02732
02733
02734
02735 static VALUE
02736 env_inspect(void)
02737 {
02738 char **env;
02739 VALUE str, i;
02740
02741 rb_secure(4);
02742 str = rb_str_buf_new2("{");
02743 env = GET_ENVIRON(environ);
02744 while (*env) {
02745 char *s = strchr(*env, '=');
02746
02747 if (env != environ) {
02748 rb_str_buf_cat2(str, ", ");
02749 }
02750 if (s) {
02751 rb_str_buf_cat2(str, "\"");
02752 rb_str_buf_cat(str, *env, s-*env);
02753 rb_str_buf_cat2(str, "\"=>");
02754 i = rb_inspect(rb_str_new2(s+1));
02755 rb_str_buf_append(str, i);
02756 }
02757 env++;
02758 }
02759 FREE_ENVIRON(environ);
02760 rb_str_buf_cat2(str, "}");
02761 OBJ_TAINT(str);
02762
02763 return str;
02764 }
02765
02766
02767
02768
02769
02770
02771
02772
02773
02774
02775 static VALUE
02776 env_to_a(void)
02777 {
02778 char **env;
02779 VALUE ary;
02780
02781 rb_secure(4);
02782 ary = rb_ary_new();
02783 env = GET_ENVIRON(environ);
02784 while (*env) {
02785 char *s = strchr(*env, '=');
02786 if (s) {
02787 rb_ary_push(ary, rb_assoc_new(env_str_new(*env, s-*env),
02788 env_str_new2(s+1)));
02789 }
02790 env++;
02791 }
02792 FREE_ENVIRON(environ);
02793 return ary;
02794 }
02795
02796
02797
02798
02799
02800
02801
02802
02803 static VALUE
02804 env_none(void)
02805 {
02806 return Qnil;
02807 }
02808
02809
02810
02811
02812
02813
02814
02815
02816 static VALUE
02817 env_size(void)
02818 {
02819 int i;
02820 char **env;
02821
02822 rb_secure(4);
02823 env = GET_ENVIRON(environ);
02824 for(i=0; env[i]; i++)
02825 ;
02826 FREE_ENVIRON(environ);
02827 return INT2FIX(i);
02828 }
02829
02830
02831
02832
02833
02834
02835
02836 static VALUE
02837 env_empty_p(void)
02838 {
02839 char **env;
02840
02841 rb_secure(4);
02842 env = GET_ENVIRON(environ);
02843 if (env[0] == 0) {
02844 FREE_ENVIRON(environ);
02845 return Qtrue;
02846 }
02847 FREE_ENVIRON(environ);
02848 return Qfalse;
02849 }
02850
02851
02852
02853
02854
02855
02856
02857
02858
02859
02860 static VALUE
02861 env_has_key(VALUE env, VALUE key)
02862 {
02863 char *s;
02864
02865 rb_secure(4);
02866 s = StringValuePtr(key);
02867 if (memchr(s, '\0', RSTRING_LEN(key)))
02868 rb_raise(rb_eArgError, "bad environment variable name");
02869 if (getenv(s)) return Qtrue;
02870 return Qfalse;
02871 }
02872
02873
02874
02875
02876
02877
02878
02879
02880 static VALUE
02881 env_assoc(VALUE env, VALUE key)
02882 {
02883 char *s, *e;
02884
02885 rb_secure(4);
02886 s = StringValuePtr(key);
02887 if (memchr(s, '\0', RSTRING_LEN(key)))
02888 rb_raise(rb_eArgError, "bad environment variable name");
02889 e = getenv(s);
02890 if (e) return rb_assoc_new(key, rb_tainted_str_new2(e));
02891 return Qnil;
02892 }
02893
02894
02895
02896
02897
02898
02899
02900
02901 static VALUE
02902 env_has_value(VALUE dmy, VALUE obj)
02903 {
02904 char **env;
02905
02906 rb_secure(4);
02907 obj = rb_check_string_type(obj);
02908 if (NIL_P(obj)) return Qnil;
02909 env = GET_ENVIRON(environ);
02910 while (*env) {
02911 char *s = strchr(*env, '=');
02912 if (s++) {
02913 long len = strlen(s);
02914 if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) {
02915 FREE_ENVIRON(environ);
02916 return Qtrue;
02917 }
02918 }
02919 env++;
02920 }
02921 FREE_ENVIRON(environ);
02922 return Qfalse;
02923 }
02924
02925
02926
02927
02928
02929
02930
02931
02932 static VALUE
02933 env_rassoc(VALUE dmy, VALUE obj)
02934 {
02935 char **env;
02936
02937 rb_secure(4);
02938 obj = rb_check_string_type(obj);
02939 if (NIL_P(obj)) return Qnil;
02940 env = GET_ENVIRON(environ);
02941 while (*env) {
02942 char *s = strchr(*env, '=');
02943 if (s++) {
02944 long len = strlen(s);
02945 if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) {
02946 VALUE result = rb_assoc_new(rb_tainted_str_new(*env, s-*env-1), obj);
02947 FREE_ENVIRON(environ);
02948 return result;
02949 }
02950 }
02951 env++;
02952 }
02953 FREE_ENVIRON(environ);
02954 return Qnil;
02955 }
02956
02957
02958
02959
02960
02961
02962
02963
02964 static VALUE
02965 env_key(VALUE dmy, VALUE value)
02966 {
02967 char **env;
02968 VALUE str;
02969
02970 rb_secure(4);
02971 StringValue(value);
02972 env = GET_ENVIRON(environ);
02973 while (*env) {
02974 char *s = strchr(*env, '=');
02975 if (s++) {
02976 long len = strlen(s);
02977 if (RSTRING_LEN(value) == len && strncmp(s, RSTRING_PTR(value), len) == 0) {
02978 str = env_str_new(*env, s-*env-1);
02979 FREE_ENVIRON(environ);
02980 return str;
02981 }
02982 }
02983 env++;
02984 }
02985 FREE_ENVIRON(environ);
02986 return Qnil;
02987 }
02988
02989
02990
02991
02992
02993
02994
02995 static VALUE
02996 env_index(VALUE dmy, VALUE value)
02997 {
02998 rb_warn("ENV.index is deprecated; use ENV.key");
02999 return env_key(dmy, value);
03000 }
03001
03002
03003
03004
03005
03006
03007
03008
03009 static VALUE
03010 env_to_hash(void)
03011 {
03012 char **env;
03013 VALUE hash;
03014
03015 rb_secure(4);
03016 hash = rb_hash_new();
03017 env = GET_ENVIRON(environ);
03018 while (*env) {
03019 char *s = strchr(*env, '=');
03020 if (s) {
03021 rb_hash_aset(hash, env_str_new(*env, s-*env),
03022 env_str_new2(s+1));
03023 }
03024 env++;
03025 }
03026 FREE_ENVIRON(environ);
03027 return hash;
03028 }
03029
03030
03031
03032
03033
03034
03035
03036
03037
03038 static VALUE
03039 env_reject(void)
03040 {
03041 return rb_hash_delete_if(env_to_hash());
03042 }
03043
03044
03045
03046
03047
03048
03049
03050
03051 static VALUE
03052 env_shift(void)
03053 {
03054 char **env;
03055
03056 rb_secure(4);
03057 env = GET_ENVIRON(environ);
03058 if (*env) {
03059 char *s = strchr(*env, '=');
03060 if (s) {
03061 VALUE key = env_str_new(*env, s-*env);
03062 VALUE val = env_str_new2(getenv(RSTRING_PTR(key)));
03063 env_delete(Qnil, key);
03064 return rb_assoc_new(key, val);
03065 }
03066 }
03067 FREE_ENVIRON(environ);
03068 return Qnil;
03069 }
03070
03071
03072
03073
03074
03075
03076
03077
03078 static VALUE
03079 env_invert(void)
03080 {
03081 return rb_hash_invert(env_to_hash());
03082 }
03083
03084 static int
03085 env_replace_i(VALUE key, VALUE val, VALUE keys)
03086 {
03087 if (key != Qundef) {
03088 env_aset(Qnil, key, val);
03089 if (rb_ary_includes(keys, key)) {
03090 rb_ary_delete(keys, key);
03091 }
03092 }
03093 return ST_CONTINUE;
03094 }
03095
03096
03097
03098
03099
03100
03101
03102
03103 static VALUE
03104 env_replace(VALUE env, VALUE hash)
03105 {
03106 volatile VALUE keys;
03107 long i;
03108
03109 keys = env_keys();
03110 if (env == hash) return env;
03111 hash = to_hash(hash);
03112 rb_hash_foreach(hash, env_replace_i, keys);
03113
03114 for (i=0; i<RARRAY_LEN(keys); i++) {
03115 env_delete(env, RARRAY_PTR(keys)[i]);
03116 }
03117 return env;
03118 }
03119
03120 static int
03121 env_update_i(VALUE key, VALUE val)
03122 {
03123 if (key != Qundef) {
03124 if (rb_block_given_p()) {
03125 val = rb_yield_values(3, key, rb_f_getenv(Qnil, key), val);
03126 }
03127 env_aset(Qnil, key, val);
03128 }
03129 return ST_CONTINUE;
03130 }
03131
03132
03133
03134
03135
03136
03137
03138
03139
03140
03141
03142 static VALUE
03143 env_update(VALUE env, VALUE hash)
03144 {
03145 rb_secure(4);
03146 if (env == hash) return env;
03147 hash = to_hash(hash);
03148 rb_hash_foreach(hash, env_update_i, 0);
03149 return env;
03150 }
03151
03152
03153
03154
03155
03156
03157
03158
03159
03160
03161
03162
03163
03164 void
03165 Init_Hash(void)
03166 {
03167 #undef rb_intern
03168 #define rb_intern(str) rb_intern_const(str)
03169
03170 id_hash = rb_intern("hash");
03171 id_yield = rb_intern("yield");
03172 id_default = rb_intern("default");
03173
03174 rb_cHash = rb_define_class("Hash", rb_cObject);
03175
03176 rb_include_module(rb_cHash, rb_mEnumerable);
03177
03178 rb_define_alloc_func(rb_cHash, hash_alloc);
03179 rb_define_singleton_method(rb_cHash, "[]", rb_hash_s_create, -1);
03180 rb_define_singleton_method(rb_cHash, "try_convert", rb_hash_s_try_convert, 1);
03181 rb_define_method(rb_cHash,"initialize", rb_hash_initialize, -1);
03182 rb_define_method(rb_cHash,"initialize_copy", rb_hash_replace, 1);
03183 rb_define_method(rb_cHash,"rehash", rb_hash_rehash, 0);
03184
03185 rb_define_method(rb_cHash,"to_hash", rb_hash_to_hash, 0);
03186 rb_define_method(rb_cHash,"to_a", rb_hash_to_a, 0);
03187 rb_define_method(rb_cHash,"inspect", rb_hash_inspect, 0);
03188 rb_define_alias(rb_cHash, "to_s", "inspect");
03189
03190 rb_define_method(rb_cHash,"==", rb_hash_equal, 1);
03191 rb_define_method(rb_cHash,"[]", rb_hash_aref, 1);
03192 rb_define_method(rb_cHash,"hash", rb_hash_hash, 0);
03193 rb_define_method(rb_cHash,"eql?", rb_hash_eql, 1);
03194 rb_define_method(rb_cHash,"fetch", rb_hash_fetch_m, -1);
03195 rb_define_method(rb_cHash,"[]=", rb_hash_aset, 2);
03196 rb_define_method(rb_cHash,"store", rb_hash_aset, 2);
03197 rb_define_method(rb_cHash,"default", rb_hash_default, -1);
03198 rb_define_method(rb_cHash,"default=", rb_hash_set_default, 1);
03199 rb_define_method(rb_cHash,"default_proc", rb_hash_default_proc, 0);
03200 rb_define_method(rb_cHash,"default_proc=", rb_hash_set_default_proc, 1);
03201 rb_define_method(rb_cHash,"key", rb_hash_key, 1);
03202 rb_define_method(rb_cHash,"index", rb_hash_index, 1);
03203 rb_define_method(rb_cHash,"size", rb_hash_size, 0);
03204 rb_define_method(rb_cHash,"length", rb_hash_size, 0);
03205 rb_define_method(rb_cHash,"empty?", rb_hash_empty_p, 0);
03206
03207 rb_define_method(rb_cHash,"each_value", rb_hash_each_value, 0);
03208 rb_define_method(rb_cHash,"each_key", rb_hash_each_key, 0);
03209 rb_define_method(rb_cHash,"each_pair", rb_hash_each_pair, 0);
03210 rb_define_method(rb_cHash,"each", rb_hash_each_pair, 0);
03211
03212 rb_define_method(rb_cHash,"keys", rb_hash_keys, 0);
03213 rb_define_method(rb_cHash,"values", rb_hash_values, 0);
03214 rb_define_method(rb_cHash,"values_at", rb_hash_values_at, -1);
03215
03216 rb_define_method(rb_cHash,"shift", rb_hash_shift, 0);
03217 rb_define_method(rb_cHash,"delete", rb_hash_delete, 1);
03218 rb_define_method(rb_cHash,"delete_if", rb_hash_delete_if, 0);
03219 rb_define_method(rb_cHash,"keep_if", rb_hash_keep_if, 0);
03220 rb_define_method(rb_cHash,"select", rb_hash_select, 0);
03221 rb_define_method(rb_cHash,"select!", rb_hash_select_bang, 0);
03222 rb_define_method(rb_cHash,"reject", rb_hash_reject, 0);
03223 rb_define_method(rb_cHash,"reject!", rb_hash_reject_bang, 0);
03224 rb_define_method(rb_cHash,"clear", rb_hash_clear, 0);
03225 rb_define_method(rb_cHash,"invert", rb_hash_invert, 0);
03226 rb_define_method(rb_cHash,"update", rb_hash_update, 1);
03227 rb_define_method(rb_cHash,"replace", rb_hash_replace, 1);
03228 rb_define_method(rb_cHash,"merge!", rb_hash_update, 1);
03229 rb_define_method(rb_cHash,"merge", rb_hash_merge, 1);
03230 rb_define_method(rb_cHash, "assoc", rb_hash_assoc, 1);
03231 rb_define_method(rb_cHash, "rassoc", rb_hash_rassoc, 1);
03232 rb_define_method(rb_cHash, "flatten", rb_hash_flatten, -1);
03233
03234 rb_define_method(rb_cHash,"include?", rb_hash_has_key, 1);
03235 rb_define_method(rb_cHash,"member?", rb_hash_has_key, 1);
03236 rb_define_method(rb_cHash,"has_key?", rb_hash_has_key, 1);
03237 rb_define_method(rb_cHash,"has_value?", rb_hash_has_value, 1);
03238 rb_define_method(rb_cHash,"key?", rb_hash_has_key, 1);
03239 rb_define_method(rb_cHash,"value?", rb_hash_has_value, 1);
03240
03241 rb_define_method(rb_cHash,"compare_by_identity", rb_hash_compare_by_id, 0);
03242 rb_define_method(rb_cHash,"compare_by_identity?", rb_hash_compare_by_id_p, 0);
03243
03244
03245
03246
03247
03248
03249
03250
03251
03252
03253 origenviron = environ;
03254 envtbl = rb_obj_alloc(rb_cObject);
03255 rb_extend_object(envtbl, rb_mEnumerable);
03256
03257 rb_define_singleton_method(envtbl,"[]", rb_f_getenv, 1);
03258 rb_define_singleton_method(envtbl,"fetch", env_fetch, -1);
03259 rb_define_singleton_method(envtbl,"[]=", env_aset, 2);
03260 rb_define_singleton_method(envtbl,"store", env_aset, 2);
03261 rb_define_singleton_method(envtbl,"each", env_each_pair, 0);
03262 rb_define_singleton_method(envtbl,"each_pair", env_each_pair, 0);
03263 rb_define_singleton_method(envtbl,"each_key", env_each_key, 0);
03264 rb_define_singleton_method(envtbl,"each_value", env_each_value, 0);
03265 rb_define_singleton_method(envtbl,"delete", env_delete_m, 1);
03266 rb_define_singleton_method(envtbl,"delete_if", env_delete_if, 0);
03267 rb_define_singleton_method(envtbl,"keep_if", env_keep_if, 0);
03268 rb_define_singleton_method(envtbl,"clear", rb_env_clear, 0);
03269 rb_define_singleton_method(envtbl,"reject", env_reject, 0);
03270 rb_define_singleton_method(envtbl,"reject!", env_reject_bang, 0);
03271 rb_define_singleton_method(envtbl,"select", env_select, 0);
03272 rb_define_singleton_method(envtbl,"select!", env_select_bang, 0);
03273 rb_define_singleton_method(envtbl,"shift", env_shift, 0);
03274 rb_define_singleton_method(envtbl,"invert", env_invert, 0);
03275 rb_define_singleton_method(envtbl,"replace", env_replace, 1);
03276 rb_define_singleton_method(envtbl,"update", env_update, 1);
03277 rb_define_singleton_method(envtbl,"inspect", env_inspect, 0);
03278 rb_define_singleton_method(envtbl,"rehash", env_none, 0);
03279 rb_define_singleton_method(envtbl,"to_a", env_to_a, 0);
03280 rb_define_singleton_method(envtbl,"to_s", env_to_s, 0);
03281 rb_define_singleton_method(envtbl,"key", env_key, 1);
03282 rb_define_singleton_method(envtbl,"index", env_index, 1);
03283 rb_define_singleton_method(envtbl,"size", env_size, 0);
03284 rb_define_singleton_method(envtbl,"length", env_size, 0);
03285 rb_define_singleton_method(envtbl,"empty?", env_empty_p, 0);
03286 rb_define_singleton_method(envtbl,"keys", env_keys, 0);
03287 rb_define_singleton_method(envtbl,"values", env_values, 0);
03288 rb_define_singleton_method(envtbl,"values_at", env_values_at, -1);
03289 rb_define_singleton_method(envtbl,"include?", env_has_key, 1);
03290 rb_define_singleton_method(envtbl,"member?", env_has_key, 1);
03291 rb_define_singleton_method(envtbl,"has_key?", env_has_key, 1);
03292 rb_define_singleton_method(envtbl,"has_value?", env_has_value, 1);
03293 rb_define_singleton_method(envtbl,"key?", env_has_key, 1);
03294 rb_define_singleton_method(envtbl,"value?", env_has_value, 1);
03295 rb_define_singleton_method(envtbl,"to_hash", env_to_hash, 0);
03296 rb_define_singleton_method(envtbl,"assoc", env_assoc, 1);
03297 rb_define_singleton_method(envtbl,"rassoc", env_rassoc, 1);
03298
03299
03300
03301
03302
03303
03304 rb_define_global_const("ENV", envtbl);
03305 }
03306